I'm trying to add some code to a class that is inside a jar(maven dependecy) and i'm doing it in the following way:
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.get("xyz.abc.ClassInADependecy");
CtMethod method = ctClass.getDeclaredMethod("getSomeValue");
method.insertBefore("{ System.out.println(\"modified\"); }");
I'm using Spring and the above code is being called using a #Configuration annotation.
When i call the method getSomeValue nothing is printed.
Can you help me find out what i'm doing wrong?
Thank you very much.
You are only changing the implementation as it is represented in Javassists type pool. You have to make sure that the class is also loaded by the respective class loader. Also, this must happen before the class is loaded for the first time, i.e. before your Spring application loads that class.
One way to do so is to manipulate the class from a Java agent: https://docs.oracle.com/javase/7/docs/api/java/lang/instrument/package-summary.html
Related
I am trying to find a way how to programatically create bean in quarkus DI, but without success. Is it possible in this framework? It seems that BeanManager does not implement the needed method yet.
First, we should clarify what "programatically create bean" exactly means.
But first of all, we should define what "bean" means. In CDI, we talk about beans in two meanings:
Component metadata - this one describes the component attributes and how a component instance is created; the SPI is javax.enterprise.inject.spi.Bean
Component instance - the real instance used in application; in the spec we call it "contextual reference".
The metadata is usually derived from the application classes. Such metadata are "backed by a class". By "backed by a class" I mean all the kinds described in the spec. That is class beans, producer methods and producer fields.
Now, if you want to programatically obtain a component instance (option 2), you can:
Inject javax.enterprise.inject.Instance; see for example the Weld docs
Make use of CDI.current().select(Foo.class).get()
Make use of quarkus-specific Arc.container().instance(Foo.class).get()
However, if you want to add/register a component metadata that is not backed by a class (option 2), you need to add an extension that makes use of quarkus-specific SPIs, such as BeanRegistrar.
If you are looking for Quarkus equivalent of Spring #Configuration then you want "bean producer" (as mentioned in comments above)
Here is an example(koltin) of how to manually register a clock:
import java.time.Clock
import javax.enterprise.context.ApplicationScoped
import javax.enterprise.inject.Produces
#ApplicationScoped
class AppConfig {
#Produces
#ApplicationScoped
fun utcClock(): Clock {
return Clock.systemUTC()
}
}
#Produces is actually not required if method is already annotated with #ApplicationScoped
#ApplicationScoped at class level of AppConfig is also not required
Although, I find those extra annotations useful, especially if are used to Spring.
You can inject your beans using Instance:
#Inject
public TestExecutorService(final ManagedExecutor managedExecutor,
final Instance<YourTask> YourTask) {
this.managedExecutor = managedExecutor;
this.YourTask= YourTask;
}
And if you need to create more than one Instance you can use the managed executor:
tasks.forEach(task -> managedExecutor.submit(task::execute));
Keep in mind that depending on the way you start the bean you may need to destroy it and only the "creator class" has its reference, meaning you have to create and destroy the bean in the same classe (you can use something like events to handle that).
For more information please check: CDI Documentation
I've learned a lot recently about Spring and one thing i think i might be misunderstanding is the #Autowired annotation, especially when using it in constructors. You see, the app i'm developing is a service so basically EVERYTHING is initialized within a constructor. The only actual user-driven events that happen are buttons that restart certain modules of the service. This is my main method :
ConfigurableApplicationContext ctx = new SpringApplicationBuilder(MDHIS_Service.class)
.headless(false).web(false).run(args);
java.awt.EventQueue.invokeLater(() ->
{
MDHIS_Service frame = ctx.getBean(MDHIS_Service.class);
frame.setSize(1024, 768);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
This is the constructor of my main class, where basically everything happens. I have omitted the calls to the methods initializing each module to shorten it :
#Autowired
public MDHIS_Service(GlobalParamService globalParamService, LogEntryService logentryService, InterfaceService interfaceService,
ConnectionService connectionService, OutboundMessageService outboundMessageService, OutboundMessageHistoryService outboundMessageHistoryService,
InboundMessageService inboundMessageService, FacilityService facilityService, ModuleStatusService moduleStatusService,
SequenceService sequenceService)
{
this.globalParamService = globalParamService;
this.logEntryService = logentryService;
this.interfaceService = interfaceService;
this.connectionService = connectionService;
this.outboundMessageService = outboundMessageService;
this.outboundMessageHistoryService = outboundMessageHistoryService;
this.inboundMessageService = inboundMessageService;
this.facilityService = facilityService;
this.moduleStatusService = moduleStatusService;
this.sequenceService = sequenceService;
}
My main class has a private final global variable for each service. Each module is a separate thread and i'm finding myself having to pass those variables to the constructor of each module which in term stores them into it own private final variables. The way i'm doing things right now #Autowired is pretty much useless since i'm having to pass the instance around. Is there a way to better use #Autowired? This service is used as the backend for a large web app and i find myself making much better use of the annotation in there. I did a lot of research on this topic and i did try the #PostContruct annotation but all i ever got was null services.
Any help would be appreciated.
Thanks!
I figured out my problem, and it was a pretty dumb one. First off, i had not annotated my main class with #Component so Spring never bothered to inject the dependencies in it. Secondly, I did not realize that a method annotated with #PostContruct would run by itself after the constructor runs WITHOUT NEEDING TO EXPLICITELY BE CALLED!
I moved all my initialization code to an init method annotated with #PostConstruct and annotated my main class with #Component, everything is working now!
You typicall don't have to use a constructor + #Autorwired, you can directly use autowired on fields and spring would fill the dependencies for you:
#Component
public class MDHIS_Service {
#Autowired
private GlobalParamService globalParamService;
}
What is important to understand is that for spring to work, you must let it create the objects for you, and not calling the constructors explicitely. It would then fill the dependencies as needed. This is done by declaring the service as a component (for example with the #Component annotation) and never create the service yourself but getting them from dependency injection.
The first object you start with has to have been created by spring and returned by the application context.
What you gain in exchange is that you don't have to forwared everything explicitely. A sub-sub-sub service quite distant from the root of the application can depend on anything it has visibility without you having to forward the reference all the way.
I would advise to take a look a the spring reference documentation, it quite detailled and complete:
https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#spring-core
Edit: I'll try to clarify a bit with an example... What do the init code of the various service actually does ?
Maybe it set the dependencies. Then just autowire them:
#Component
MySubService {
#Autowired MySubSubService mySubSubService;
}
Maybe it does some more thing than setting fields so you can add on top an init method that do it and this init method can eventually call the other services.
#Component
MySubService {
#Autowired MySubSubService mySubSubService;
#PostConstruct
public void init() {
//Init code that may use mySubSubService.
}
}
You don't have to declare a constructor and forward dependencies yourself, sprint does it for you.
The only case where you'd have problem is if finally you need some parameters that are not dependency to the init method. But even in that case you could do it from you main code. That's actually what you did with the main service calling the various setters rather than messing with the constructor to set theses values.
I'm hoping to make some calls to solr using Alfresco's org.alfresco.repo.search.impl.solr.SolrAdminHTTPClient class. However that bean search.solrAdminHTTPCLient does not seem to be accessible to me from the standard application context. Attempting to add a dependency and property reference for my own bean (via xml) has failed as well. Any reason this is not accessible?
public class MyClass extends DeclarativeWebScript implements ApplicationContextAware{
...
SolrAdminHTTPClient adminClient = (SolrAdminHTTPClient) appContext.getBean("search.solrAdminHTTPCLient");
Would like to avoid creating my own clients for standard solr admin queries.
Judging by the folder tree leading to this file, I would say that bean is available in the search SubSystem which means it lives completely in a different context, a child context in fact.
So you need to lookup that context first, before trying to retrieve your bean !
UPDATE: I have done some digging, and I guess that your window to that child context is in this particular bean.
So I think you can do the following :
SwitchableApplicationContextFactory search = (SwitchableApplicationContextFactory)applicationContext.getBean("Search");
ApplicationContext searchCtx = search.getApplicationContext();
SolrAdminHTTPClient adminClient = (SolrAdminHTTPClient) searchCtx.getBean("search.solrAdminHTTPCLient");
A friend from the IRC channel has however suggested an alternative solution:
Set up a seperate ChildApplicationContextFactory for Each and every bean you which to access in your child context, and he suggested you get some inspiration from this.
I have had chance of working on only one project using spring , and the way it worked was
Make a singleton class (lets say MySpringHelper), that has method like getBean(String beanName)
What getBean(String) does is, it first checks existence of applicationContext, if it exists uses same to get the bean , else creates new applicationContext and returns the bean
Wherever in you project you need a bean simply call MySpringHelper.getBean("abc")
Keeping this in mind , when i was studying spring , i noticed interface "ApplicationContextAware" ... I am not sure when will this be needed, uses above pattern such interface seems not of any use. Or the above Singleton MySpringHelper pattern/approach is incorrect ??
Looking forward to learn from your experience
To give more details on application , its like a pdf file generator, 1 pdf file having 12-15 different charts, so the main method runs 1 thread for each chart , and inside these chart logic we are using singleton MySpringHelper
Why are you checking the existance of applicationContext? It should be there if your helper bean is configured in xml and has setter method in it. There is no need to create application context in that case.
For your case, I would suggest you get applicationContext injected by Spring rather than by using ApplicationContextAware.
I am using spring mvc 2.5 . I have a serializable class (For instance A class), but now I use this A class as command class.
Can a serializable class be used as command class? If yes, how?
In servlet, I define this A class as command class, in formbacking method, I created object from this A class but in formbacking, when I try to return the object created by this A class, it is not successful.
Additionally, I want to save data coming from jsp file into database by using A.hbm.xml
I have solved the problem. It is not important that class is serilizable class or not. Mapping can be done correctly.