WeldClientProxy cannot be cast - cdi

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".

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:
[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}).
[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.

Related

How to decorate the final class DocumentGenerator

I am having problems to decorate the final class "DocumentGenerator" (in vendor/shopware/core/Checkout/Document/Service/DocumentGenerator.php) and overwrite the "generate" function inside of it.
I tried to decorate it the usual way, but an error is thrown because the "DocumentController" class excepts the original class and not my decorated one?
Argument 2 passed to Shopware\Core\Checkout\Document\DocumentGeneratorController::__construct() must be an instance of Shopware\Core\Checkout\Document\Service\DocumentGenerator
Its also not possible to extend from the class in my decorated class, because the "DocumentGenerator" is a final class.
My goal is to execute additional code, after an order document is generated. Previously I successfully used to decorate the "DocumentService" Class, but its marked as deprecated and shouldnt be used anymore. Also the "DocumentGenerator" class is used for the new "bulkedit" function for documents as of Version 6.4.14.0
I'm grateful for every tip.
As #j_elfering already wrote it's by design that you should not extend that class and therefore also shouldn't decorate it.
To offer a potential alternative:
Depending on what you want to do after a document has been generated it might be enough to add a subscriber to listen to document.written, check if it was a new document created and then work with the data from the payload for fetching/persisting data depending on that.
public static function getSubscribedEvents()
{
return [
'document.written' => 'onDocumentWritten',
];
}
public function onDocumentWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $result) {
if ($result->getOperation() !== EntityWriteResult::OPERATION_INSERT) {
// skip if the it's not a new document created
continue;
}
$payload = $result->getPayload();
// do something with the payload
}
}
Probably not what you want to hear but: The service is final in purpose as it is not intended to be decorated.
So the simple answer is you can't. Depending on your use case there may be other ways that don't rely on decoration.

Dynamic type inferring, or custom VariableScope. How is it done correctly?

I have a scripting system where depending on where the script is executed you have access to different variables. I also want to have inferred types for a type of Auto-Completion for the script editor.
But when the types are inferred during the compile phase, I have no way of giving a Binding which explains to the compilation phase what types those dynamic variables have.
I have currently solved this by:
Not compiling the code with either #TypeChecked nor #CompileStatic but later manually running a subclassed StaticCompilationVisitor on the dynamically typed codebase and manually filling in the StaticTypesMarker.INFERRED_TYPE inside visitVariableExpression() for the dynamic variables that I know exists.
However, this seems like the wrong way to go about it, and I would actually like to work with the VariableScope instead. But it seems to be under rough lockdown inside the VariableScopeVisitor, so it's difficult to pop in a CustomVariableScope that dynamically does the lookups. I have managed to do this with reflection, replacing the VariableScopeVisitor inside CompilationUnit and currentScope and such inside VaribleScopeVisitor. It works, but I don't like working against hard-coded private field names.
This might be a long-winded way of asking: Is there an official way of handling a situation of static typing with dynamic variables? I cannot do this by setting scriptBaseClass for reasons too complex to explain here.
If the question is unclear, please tell me and I'll try to edit in better explanations.
The answer was to add a GroovyTypeCheckingExtensionSupport to a StaticTypeCheckingVisitor and then use visitClass on the first ClassNode of the CompilationUnit.
final ClassNode classNode = this.compilationUnit.getFirstClassNode();
final StaticCompilationVisitor visitor = new StaticCompilationVisitor(this.sourceUnit, classNode);
visitor.addTypeCheckingExtension(new MyGroovyTypeCheckingExtensionSupport(visitor, this.compilationUnit));
visitor.visitClass(classNode);
visitor.performSecondPass();
And create something like the class below:
private static class MyGroovyTypeCheckingExtensionSupport extends GroovyTypeCheckingExtensionSupport {
private static final ClassNode CLASSNODE_OBJECT = ClassHelper.make(Object.class);
public MyGroovyTypeCheckingExtensionSupport(StaticTypeCheckingVisitor typeCheckingVisitor, CompilationUnit compilationUnit) {
super(typeCheckingVisitor, "", compilationUnit);
}
#Override
public boolean handleUnresolvedVariableExpression(VariableExpression vexp) {
final ClassNode type = this.getType(vexp);
if (type == null || type.equals(CLASSNODE_OBJECT)) {
if (vextp.getName().equals("something")) {
this.storeType(vexp, ClassHelper.make(SomeClass.class));
return true;
}
}
return false;
}
}

Optional arguments on interface and class can conflict

I have just come across an interesting gotcha where optional arguments on an interface and the implementing class can conflict.
I found this out the hard way (school boy error) whilst experimenting. You cannot spot it in the debugger and I assumed it was me messing up the dependency injection.
I'm guessing this is so an alternative interface can give a differing view on what default behaviour should be?
Is there a compiler warning or style cop rule to help point this out?
public interface MyInterface
{
MyStuff Get(bool eagerLoad = true); //this overrules the implementation.
}
public class MyClass : MyInterface
{
public MyStuff Get(bool eagerLoad = false) //will still be true
{
//stuff
}
}
Remember default arguments are a compile-time feature. The compiler picks up the default argument based on the static type of the reference in question and inserts the appropriate default argument. I.e. if you reference is of the interface type you get one behavior but if the reference is of the class type you get the other in your case.

Liferay - Hook for GroupWrapper

I'm trying to override the getDescriptiveName() method in com.liferay.portal.model.Group
I found a wrapper (com.liferay.portal.model.GroupWrapper), so I tried to write a hook as written in the documentation :
liferay-hook.xml:
<service>
<service-type>com.liferay.portal.model.GroupWrapper</service-type>
<service-impl>fr.villedeniort.hook.expando.GroupWrapperImpl</service-impl>
</service>
fr.villedeniort.hook.expando.GroupWrapperImpl.java:
public class GroupWrapperImpl extends GroupWrapper {
public GroupWrapperImpl(Group group) {
super(group);
}
#Override
public java.lang.String getDescriptiveName()
throws com.liferay.portal.kernel.exception.PortalException,
com.liferay.portal.kernel.exception.SystemException {
return super.getDescriptiveName();
}
When the hook is deployed, it raises an exception :
java.lang.NoSuchMethodException: fr.villedeniort.hook.expando.GroupWrapperImpl.<init>(com.liferay.portal.model.GroupWrapper)
I browse the code I found out that it breaks at this part for a reason I ignore:
Constructor<?> serviceImplConstructor = serviceImplClass.getConstructor(new Class<?>[] {serviceTypeClass});
At this point, variables have theses values:
serviceType "com.liferay.portal.model.GroupWrapper" (id=14829)
serviceImpl "fr.villedeniort.hook.expando.GroupWrapperImpl" (id=14830)
serviceTypeClass Class<T> (com.liferay.portal.model.GroupWrapper) (id=14831)
serviceImplClass Class<T> (fr.villedeniort.hook.expando.GroupWrapperImpl) (id=14832)
Do you have any idea?
Thanks!
You should have also a constructor without any argument. Now you have one with constuctor arguments, but there is no pure class constructor that java searches when it makes class instance. After calling the pure constructor java then calls the argumented one.
I had similar case in some other context and this was the solution. <init> tag on the error message refers on this kind of issue.
Apparently, it's not possible to hook other classes than Services, so I had to find a different way. For my case, I hooked a JSP and wrote my own method to get the right descriptive name from the hook.

which spring ws jaxb annotation to change xml element name

I am using a sping ws endpoint with jaxb marshalling/unmarshalling to proudce a list of Organisation objects (our local type). The endpoint is SOAP 1.1, no parameters supplied on the request message.
I understand JAXB doesn't handle lists very well, so I use a wrapper class.
#XmlRootElement(name="orgResponse", namespace=....)
public class OrganisationListWrapper {
private ArrayList<Organisation> organisationList;
public getOrganisationList() {
return organisationList;
}
public setOrganisationList(ArrayList<Organisation> organisationList) {
this.organisationList = organisationList;
}
}
The endpoint....
#PayloadRoot(localPart=.... namespace=....)
#ResponsePayload
public OrganisationListWrapper getOrganisations() {
OrganisationListWrapper wrapper = new OrganisationListWrapper();
wrapper.setOrganisationList(.... call service layer get list ....);
return wrapper;
}
This works fine and I get a SOAP payload with
<orgResponse>
<organisationList>
... contents of organisation 1
</organisationList>
<organisationList>
... comtents of organisation 2
</organisationList>
.... etc ....
</orgResponse>
The Organisation class is not JAXB annotated. It is part of a large list of pre-existing classes that are being exposed through web services for the first time. Trying to get by without going in and annotating them all by hand.
I was able to override the name OrganisationWrapper with orgResponse in the XmlRootElement annotation. I would like to override the organisationList name in the child element with organisation but haven't been able to find an annotation that does this.
I can replace the array list name with organisation and it will work fine, but our coding standard here required us to put List on the end of our list names. I would like to try and stick to that. I have tried XmlElement, but that produced a jaxb exception.
Any suggestions would be appreciated.
Because JAXB default the access type to PUBLIC_MEMBER, make sure you annotate the property (getter) and not the field:
#XmlElement(name="organisation")
public getOrganisationList() {
return organisationList;
}
If you want to annotate the field then add the following annotation to your class:
#XmlAccessorType(XmlAccessType.FIELD)

Resources