0

I use the Unbound ID library that has a class LDAPConnection which has no default constructor and which implements LDAPInterface. I produce the LDAPConnection as follows:

@Produces
@SimpleLdapConnection
@ApplicationScoped
public LDAPInterface createLdapConnection() throws GeneralSecurityException, LDAPException {
    LDAPConnection conn = new LDAPConnection(host, port, username, password);
    return conn;
}

I now want to inject this LDAPConnection class to a second producer, which should generate a Connection Pool:

@Inject
@SimpleLdapConnection
LDAPInterface simpleLdapConnection;

@Produces
@Default
@ApplicationScoped
public LDAPInterface produceLdapConnectionPool() throws GeneralSecurityException, LDAPException {
    LDAPConnectionPool pool = new LDAPConnectionPool((LDAPConnection)simpleLdapConnection.g, connectionPoolInitialSize, connectionPoolMaxSize);
    return pool;
}

To create the LDAPConnectionPool, I need to cast the simpleLdapConnection to an LDAPConnection (as it must be an LDAPConnection).

However, I get the error:

java.lang.ClassCastException: org.jboss.weld.proxies.LDAPInterface$1687649628$Proxy$_$$_WeldClientProxy cannot be cast to com.unboundid.ldap.sdk.LDAPConnection

at at.rsg.lp.benutzerverwaltung.business.repository.LdapConnectionPoolProvider.produceLdapConnectionPool(LdapConnectionPoolProvider.java:59)

How can I get around this error? P.S. changing the first producer to return an LDAPConnection does not work as I get the error "Injected normal scoped bean is not proxyable".

stefan.m
  • 1,912
  • 4
  • 20
  • 36
  • The problem seems to be caused by the fact that LDAPConnection is final. This forces Weld to create such a proxy. One (albeit ugly) solution is to write a non-final wrapper class. – stefan.m Aug 10 '18 at 14:43
  • Do you really need the `LDAPConnection` exposed as a CDI bean? If not you can simply hide its existence within `produceLdapConnectionPool()`, i.e. the `new LDAPConnection(...)` occurs within that method, you use the local variable to create the `LDAPConnectionPool` and forget about it. – Nikos Paraskevopoulos Aug 10 '18 at 15:00
  • 1
    Thinking a bit more the wrapper you mention, which is of course a viable solution, might not be that ugly after all. Actually, creating a "wrapper" *layer* of objects on top of the Unbound ID API might be a good idea that will uncouple your implementation from it and might even yield more benefits, e.g. testability/mock-ability. At the cost of more code of course. – Nikos Paraskevopoulos Aug 10 '18 at 15:13
  • Exposing the `LDAPConnection` as a bean is not really necessary, but I then come to a similar problem when using produceLdapConnectionPool. There are reason why I need to cast to that one too, and then again such an exception occurs. So wrapper is probably the way to go... – stefan.m Aug 10 '18 at 15:22

1 Answers1

1

What you are running into, from CDI point of view, are the defined bean types of a producer method. This is backed by CDI specification.

In short, for producer methods, the bean types are derived from return types and the interfaces it implements. E.g. the actual implementation type is not included. The reason for that is exactly what you see when you saw when you tried to return the actual implementation type - impls often contain final methods or other bumps making them unproxyable.

There are two things I can think of to solve this:

  1. [This one is likely to fail] Try putting @Typed annotation on your producer - I doubt it will work in this case, but it could be worth a shot. This annotation declares all the types the bean will have. You would use it like this - @Typed({LDAPInterface, LDAPConnection}).
  2. [This should be a go-to option] If I were you, I would create a wrapper object just like you suggested. It won't really be all that ugly, just few bits and pieces of code should do the trick.
Siliarus
  • 6,393
  • 1
  • 14
  • 30
  • 1) sounds like a good idea, but as you assumed, it does not work (the same ClassCastException occurs). 2) works of course. – stefan.m Aug 13 '18 at 10:41