Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>There is a sweet little class called a <code>DynamicObjectAdapterFactory</code> posted by <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=109017" rel="nofollow">Heinz Kabutz</a> which uses generics and reflection to adapt an object to implement an interface by providing it with a source class that already implements the interface.</p> <p>Using it like below you can wrap your <code>INSTANCE</code> in a proxy. Of course the resulting object is no longer an <code>enum</code> but it <strong>does</strong> retain all of the singletonness of the <code>enum</code> I think. It also, obviously - can use any object to implement your interface.</p> <p>I think this is as close as you will get to an <code>enum</code> extending a class.</p> <p>Here's some test code that seems to work. Obviously the object is no longer an <code>enum</code> but as your aim was a singleton this may be acceptable.</p> <pre><code>public class Test { // To implement this. public interface Implement { public void init(); public void connect(); public void disconnect(); public boolean isConnected(); } // An implementor that does implement. public static class Implements implements Implement { @Override public void init() { } @Override public void connect() { } @Override public void disconnect() { } @Override public boolean isConnected() { return false; } } // Extend the INSTANCE in this. public enum Extend { INSTANCE; // Hold my adapted version - thus still a singleton. public final Implement adaptedInstance; Extend () { // Use the constructor to adapt the instance. adaptedInstance = DynamicObjectAdapterFactory.adapt(this, Implement.class, new Implements()); } } // Provides an INSTANCE that has been extended by an Implements to implement Implement. public static Implement getInstance () { return Extend.INSTANCE.adaptedInstance; } public void test() { System.out.println("Hello"); Implement i = getInstance(); } public static void main(String args[]) { new Test().test(); } } </code></pre> <p>Here's the DynamicObjectAdapterFactory - I've tweaked it a little from the original - I hope Dr. Kabutz does not object.</p> <pre><code>public class DynamicObjectAdapterFactory { // Use methods in adaptee unless they exist in target in which case use adapter. // Implement target in passing. public static &lt;T&gt; T adapt(final Object adaptee, final Class&lt;T&gt; target, final Object adapter) { return (T) Proxy.newProxyInstance( Thread.currentThread().getContextClassLoader(), new Class[]{target}, new InvocationHandler() { private final String name = adaptee.getClass().getSimpleName() + "(" + adaptee.toString() + ")" + "+" + adapter.getClass().getSimpleName() + "(" + adapter.toString() + ")"; // The methods I wish to adapt. private Map&lt;MethodIdentifier, Method&gt; adaptedMethods = new HashMap&lt;&gt;(); { // initializer block - find all methods in adapter object Method[] methods = adapter.getClass().getDeclaredMethods(); for (Method m : methods) { // Keep a map of them. adaptedMethods.put(new MethodIdentifier(m), m); } } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // Has it been adapted? Method otherMethod = adaptedMethods.get(new MethodIdentifier(method)); if (otherMethod != null) { return otherMethod.invoke(adapter, args); } else { return method.invoke(adaptee, args); } } catch (InvocationTargetException e) { throw e.getTargetException(); } } @Override public String toString() { StringBuilder s = new StringBuilder(); // Really simple. May get more flexible later. s.append("Adapted: ").append(name); return s.toString(); } }); } private static class MethodIdentifier { private final String name; private final Class[] parameters; public MethodIdentifier(Method m) { name = m.getName(); parameters = m.getParameterTypes(); } @Override public boolean equals(Object o) { // I am always equal to me. if (this == o) { return true; } // I cannot be equal to something of a different type. if (!(o instanceof MethodIdentifier)) { return false; } MethodIdentifier mid = (MethodIdentifier) o; return name.equals(mid.name) &amp;&amp; Arrays.equals(parameters, mid.parameters); } @Override public int hashCode() { return name.hashCode(); } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload