Injecting spring service in external groovy class created at runtime - java

I have an Spring-powered app and want to integrate groovy. Specifically, I have one abstract java class with a set of abstract method definitions and one repository inyected with autowired.
This class must be implemented by several final groovy external classes (one for each client).
At this moment, I am calling the Groovy class in java this way:
final Class parsedClass = groovyClassLoader.parseClass(groovyFile);
final GroovyObject groovyObject = (GroovyObject) parsedClass.newInstance();
final Object response = groovyObject.invokeMethod(methodName, methodParameters);
The problem is that I need to autowired the repository variable in each Groovy external class but currently are null.
How can I notify the Groovy class to get the inyected repository variable when I create it at runtime?
Thanks!
Edit
Y have solved it using the setProperty method from groovyObjectObject this way:
groovyObject.setProperty("myRepository", myRepositoryImpl);

The instance here is not created by spring, hence I don't think spring can automagically set the instance of repository in the groovyObject that you have.
However, if you can can autowire the repository into the class thats generating the groovyObject then you can manually inject the repo in the newInstance call.
parsedClass.newInstance(repository:your_autowired_repo_ref)

I have solved it using the setProperty method from groovyObjectObject this way:
groovyObject.setProperty("myRepository", myRepositoryImpl);

Related

Bytebuddy get value of proteced field

Im struggling to figure out how to access a protected field using ByteBuddy and what approach to take.
Background: Id like to intercept a class from a dependency I have on my class path. Im creating a junit test report and need to intercept org.assertj.core.api.AbstractAssert in order to capture the actual field value from that class.
Iv tried...
Class<?> type = new ByteBuddy()
.redefine(AbstractAssert.class)
.visit(Advice.to(MyAdvices.class).on(ElementMatchers.isMethod()))
.make().load(AbstractAssert.class.getClassLoader()).getLoaded();
log.info(type.getFields().toString());
Class already loaded: class org.assertj.core.api.AbstractAssert
Im not even sure if this is the correct approach for what Im trying to achieve
Any help appreciated
You cannot just change a class on the JVM. Either you would need to use a different class loader and load the class regularly, or a Java agent. For an agent, Byte Buddy supplies a RedefinitionStrategy which you can use to integrate this in your above example. Also have a look at the byte-buddy-agent project.

Can we prevent ourself of instanciating a Java class from an imported library

I have a library class, that is, a class that I load from a JAR, the source code is outside of my control. We instanciate it in our project in several places, and a property of the created objects should be always set. Unfortunately there is no central settings for the library, so I have created a subclass:
public class MyClass extends LibraryClass {
public MyClass() {
super();
super.setSomeProperty();
}
}
and then I replaced all instanciation of LibraryClass with MyClass. It works fine, but I want to prevent myself and my collegues to instanciate a LibraryClass in the future.
Is it possible to mark the LibraryClass (or its constructor) as deprecated by Maven or by Eclipse or somehow else? It would be a compile time solution.
Or is it possible to use some Spring/Aop magic to replace all instancieated LibraryClass with MyClass in runtime?
Since you mention to mark the constructor as deprecated (which would not actually forbid it) - if you are using something like sonar, you could create an own rule which marks the usage as error, exept for your subclass.
If you are using Spring in your application and all bean instantiation is done through Spring, on application startup check if a bean exist of type LibraryClass. Throw an exception if it exists. Similar solution can be implemented for any other framework used for bean instantiation.

Spring Java Config: How to create ProxyFactoryBean with package-private target class constructor

Given the following Java code (from a 3rd-party-library outside of my control):
package some.third.party.lib;
interface MyInterface { ... }
and the following class A with a package-private constructor (this is its only constructor):
package some.third.party.lib;
[...]
class A implements MyInterface {
A() {}
}
ProxyFactoryBean.setTargetName expects the ID of an already instantiated bean.
Since my Spring Java Config class is in an application-specific package (and I don't want to change it to some.third.party.lib), I can't instantiate class A, since it's package-private.
I'm aware that I could use reflection to temporarily change the visibility of A's constructor, but I would like to avoid this if possible.
Q: (How) can I create a Spring (4.2.1.RELEASE) ProxyFactoryBean of a class A in Spring Java Config without having to use reflection (and without having to put my Java Config Class into the same package as A)?
Please note that when using Spring XML config, this situation does not occur, because Spring (in the background) creates a Bean for class A, probably also using reflection.

Passing object to the JCL-loaded class

I have really tricky problem. I have kinda container which can run custom JAR with the method which has a class ComponentContext as a parameter. After loading I want to invoke this method with the reflection but there is a problem - I must use the same class loader (JCL in this case) to create ComponentContext. See the code:
JclObjectFactory factory = JclObjectFactory.getInstance();
Object context = factory.create(jcl, "org.hive.lib.component.ComponentContextImpl");
Method setConfigDirMethod = context.getClass().getMethod("initialize", File.class, File.class);
setConfigDirMethod.invoke(context, configDir, workspace);
Method method = instance.getClass().getMethod("initialize", context.getClass());
method.invoke(instance, context);
And when I'm trying to pass context created in container like this
ComponentContextImpl c = new ComponentContext();
It fails with java.lang.IllegalArgumentException because of another classloader.
It means that my container depends on class from the JAR, it drives me crazy. It there a way to pass my own ComponentContext (not instantiated from the JAR) to the method initialize?
PS - JAR was assembled with assembly:single
Solved as marking shared library as provided

How to use eclipse 4 DI in classes that are not attached to the application model?

I have created a OSGI service with declarative services to inject an object that implements an interface. If I inject the object in a class that is attached to the application model (handler,part,....) it is working fine. If I inject it in a class that is not attached to the application model it is always returning null.
Is it possible to use DI in classes that are not attached to the application model? I looked in the vogella tutorials but somehow I don't find a solution.
I know of three ways of how Eclipse 4 can inject objects in your classes:
During start-up the Eclipse runtime looks for relevant annotations in the classes it instantiates.
Objects injected in 1. are tracked and will be re-injected if changed.
Manually triggering injection using the ContextInjectionFactory and IEclipseContext.
What you want may be possible with the third option. Here is a code example:
ManipulateModelhandler man = new ManipulateModelhandler();
//inject the context into an object
//IEclipseContext iEclipseContext was injected into this class
ContextInjectionFactory.inject(man,iEclipseContext);
man.execute();
The problem is, however; that the IEclipseContext already needs to be injected into a class that can access the object that needs injection. Depending on the number of necessary injections, it might be more useful to use delegation instead (testability would be one argument).
#Inject
public void setFoo(Foo foo) {
//Bar is not attached to the e4 Application Model
bar.setFoo(foo);
}
Therefore, a better solution is probably using the #Creatable annotation.
Simply annotate your class, and give it a no-argument constructor.
#Creatable
public class Foo {
public Foo () {}
}
Using #Inject on that type as in the method above, will let Eclipse instantiate and inject it.
The disadvantage is that you cannot control the object creation anymore, as you would with ContextInjectionFactory.inject(..).
I refactored out some part of e(fx)clipse in order to achieve that. Have a look at this. Sorry for the shameless plug...

Categories

Resources