1

I have a lot of proxy classes around services, and all look (almost) the same. Can I reduce code duplication somehow by using a generics singleton class, that takes the Service and Port class as type parameters?

This is my completely wrong code with what I want to get started:

public class MyProxy<S extends Service, P extends BindingProvider>
{
  private static final MyProxy<S extends Service, P extends BindingProvider> instance
      = new Proxy<S extends Service, P extends BindingProvider>();
  private S service;

  public static MyProxy<S extends Service, P extends BindingProvider> getInstance() {
    return instance;
  }

}
  • The type parameters for MyProxy I assume to be correct.
  • Can I declare a static instance singleton member variable, and how?
  • The member variable service should be more easy, can I have a type parameter as a member, anyway?
  • How about the return type of getInstance(), how to I write it?
towi
  • 21,587
  • 28
  • 106
  • 187
  • By declaring a singleton, you'll have to specify wildcard and make unchecked casts then. Don't think that's what you're expecting. This shows that you implicitly consider MyProxy be a subclass of MyProxy which is semantically wrong in Java (though it might work). Maybe a reply is coming if a find a suitable solution – Antoine Marques Sep 12 '13 at 09:23
  • 1
    As a comparative example, you might have a look at java.util.Collections that has a singleton for EMPTY_LIST for example and a generic method emptyList() whose javadoc states that a new instance shall be created on each call (though the singleton could just have been casted) – Antoine Marques Sep 12 '13 at 09:25
  • @Antoine Marques: empty list is stateless while the supposed wrapper here is not. – Holger Sep 12 '13 at 09:32
  • @towi I think you are on the wrong path thinking you can collapse multiple singleton proxy classes into one *singleton* class. If you still have multiple services you want to wrap you will need *multiple* instances of your single wrapper class. – Holger Sep 12 '13 at 09:36
  • @Holger Maybe you are right. Since I come from C++ I assumed that for each different type argument I get a specialized class version generated, no? In C++ when I define `stack` the use of `stack` and `stack` creates two classes with its own static members. – towi Sep 12 '13 at 09:55
  • 1
    Generics are not templates. A single generic class remains a single class. – Holger Sep 12 '13 at 10:08
  • @Holger I did not know that. That is the answer to my question -- in a way ;-) Wrong assumption... I guess now that the "generated code" is only cast-code then, not a whole class. – towi Sep 12 '13 at 10:10
  • Inside the generic class there are not even casts. Only the code *using* a generic class might have synthetic casts where necessary. – Holger Sep 12 '13 at 10:16

2 Answers2

0

This is the code corresponding to my first comment. As i said this involves unchecked casts.

public static class MyProxy<S extends Service, P extends BindingProvider> {

    private static final MyProxy<? extends Service, ? extends BindingProvider> instance = new Proxy<Service, BindingProvider>();

    private S service;

    public static <S extends Service, P extends BindingProvider> MyProxy<S, P> getInstance() {
        return (MyProxy<S, P>) instance;
    }
}
Antoine Marques
  • 1,379
  • 1
  • 8
  • 16
  • I didn't understood though the use of the `service` field – Antoine Marques Sep 12 '13 at 09:30
  • The class is not complete yet. `service` is used by other methods. I needed a simple member variable declared from a type argument. What does the `?` mean in the `<...>´s exactly? – towi Sep 12 '13 at 09:52
  • Hrmm `new Proxy();` makes me skeptical if my approach works at all in Java, as @Holger pointed out. When I use this class twicem say `MyProxy p = new MyProxy()` and `MyProxy q = new MyProxy()` -- will I really have *two* distinguashable `instance`-members, as I intended? – towi Sep 12 '13 at 10:02
0

Here is an example for such a proxy skeleton with a single type parameter:

public class MyProxy<S extends Service> {

  private static final ConcurrentHashMap<Class<?>, MyProxy<?>> INSTANCES
      = new ConcurrentHashMap<>();

  private S service;// could be final depending on your demands
  private final Class<S> type;

  MyProxy(Class<S> serviceType, S serviceInstance) {
    service=serviceInstance;
    type=serviceType;
  }

  /**
   * Helper method for a runtime cast.
   */
  @SuppressWarnings("unchecked")
  public <S extends Service> MyProxy<S> cast(Class<S> serviceType) {
    if(serviceType!=type) throw new ClassCastException(type+" != "+serviceType);
    return (MyProxy<S>)this;
  }

  /**
   * Get the proxy for type {@code sType}.
   */
  public static <S extends Service> MyProxy<S> getInstance(Class<S> sType) {

    MyProxy<?> old=INSTANCES.get(sType);
    if(old!=null) return old.cast(sType);

    MyProxy<S> proxy=allocateNewProxy(sType);

    old=INSTANCES.putIfAbsent(sType, proxy);
    return old==null? proxy: old.cast(sType);
  }
}

So you can use it the following way:

MyProxy<A> proxyA=MyProxy.getInstance(A.class);

Assuming that A is a subclass/implementation of Service

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Can we not get rid of the `sType` parameter? `S s = new S()` followed by `INSTANCES.get(s.getClass());` -- or somethe other way to `S` to get to its class? – towi Sep 12 '13 at 10:09
  • No. Generics are implemented via type erasure so the value of a type parameter exists on compile time only. Note that `Foo.class` is not an expensive operation. – Holger Sep 12 '13 at 10:12
  • No, but a bit of code duplication, which one may get rid of. Since Java generics work in the return type as well, don't they (unlike C++). Like my code `public static T toType(String xmlString) { JAXBElement jbel = ...; return (T) jbel.getValue(); }` -- which I use often and could devise after lots of try-and-arror with my limited generics understanding. – towi Sep 12 '13 at 10:21
  • A method like `public static T toType(String xmlString)` is broken by design. I could use it to assign the result to *any* variable type which surely breaks at runtime as the result of that method cannot be of any kind. How about `Integer i=toType(xmlString);` and `Button b=toType(xmlString);`? At least one of these calls *must* break at runtime. – Holger Sep 12 '13 at 10:26
  • By the way your implementation of that `toType` method must have produced a compiler warning, for a good reason. You should not ignore it. – Holger Sep 12 '13 at 10:28
  • No, I don't think so. I cant see a warning. Although, I use netbeans and assume I get a warning in the sidebar. The console maven messages run through too fast, anyway. But let's check... No, I touched the file, `mvn compile` does only emit `[INFO]`s, no warnings, but says "Compiling 1 source file", though. Here a long [excerpt](http://pastebin.com/ykXKAscp). – towi Sep 12 '13 at 11:19
  • In case of Netbeans you might have received a message like `Note: ….java uses unchecked or unsafe operations.` – Holger Sep 12 '13 at 12:03