I am trying to scan classes with Reflections library, if I add the Dynamic Web project to another project (plain Java one), I get the classes I want, but if run inside a #Startup bean, it is empty.
Here is the code:
Reflections reflections = new Reflections(
new ConfigurationBuilder().filterInputsBy(
new FilterBuilder.Include(
FilterBuilder.prefix("my.package")
)
).setUrls(
ClasspathHelper.forJavaClassPath()
).setScanners(
new SubTypesScanner(false)
)
);
Set<Class<? extends Object>> testClasses = reflections.getSubTypesOf(Object.class);
The tv,goopi should be changed to whatever package prefix used.
the testClasses Set is empty.
If the same code is running in a different project referencing this one, no other change, then the Set is populated with all classes inside the package.
The Maven dependency for Reflections is:
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.9-RC1</version>
</dependency>
Wildfly 8.2.0.
For now, I can save the file extracted in the external project and use the load function, but this will not be dynamic as it should be.
I struggled with this one for quite a while, it looks like due to the way it works, without getting the full java class path (makes it very heavy) you should load reflect a little bit later. This is mostly due to dynamic class creation during the EJB initialization phase, Startup beans included.
To load the full class path (from a startup bean)
urls.addAll(ClasspathHelper.forJavaClassPath());
To make it cross JEE friendly,
e.g. wild-fly, you need to reflect from a Servlet Context listener. For me the right place was in the constructor but a static field may work.
public class GuiceContext implements ServletContextListener
{
#Override
public void contextInitialized(ServletContextEvent servletContextEvent)
{
ClasspathHelper.forWebInfLib(servletContextEvent.getServletContext());
ClasspathHelper.forWebInfClasses(servletContextEvent.getServletContext());
}
Try and get your beans to initialize stand-alone without dependencies. You can also use a custom injector like Guice to push your beans. In this case you would use the GuiceServletContextListener class.
You are excluding direct exclusions of Object.class, this startup bean in this instance may not be loading due to this.
new SubTypesScanner(false);
A complete library with org.reflections and guice directly implemented can be found at https://github.com/GedMarc/GuiceInjection
Related
I am looking to do some refactoring of a Java J2EE application, but I am not clear how to have CDI provide the needed dependencies:
The current setup is quite simple/easy to understand:
#ApplicationScoped
public class MyApplication {
#Inject
#Named("Default")
private Dependency dependency;
public void dostuff(){
dependency.process();
}
}
I now need a new instance of dependency each time I call dostuff.
I am unclear on how to use CDI to create this for me. My Dependency has its own dependencies that I would like CDI to create for me.
I expect there is a layer of indirection I need to add.
Additional context:
This class is part of a process that polls for work to be done, and is hosted in Wildfly.
We are not using Spring in the project.
Since what you desire is having a new instance of Dependency, each time the method is called, I think what you need is an instance of Provider that is (javax.inject.Provider<T>) injected in your class/bean.
Inject the provider to your current class:
#Inject Provider<DesiredBean> provider;
Then, in your method doStuff() obtain the new instance:
DesiredBean desiredBean = provider.get();
This should get you going.
Is there a specific reason you need to use CDI besides the dependency injection?
If not, I'd suggest making doStuff() take a Dependency object as a parameter:
public void doStuff(Dependency dependency) {
dependency.process();
}
Then, when you call the method, you provide it with a new instance of Dependency:
myApplication.doStuff(new Dependency());
That way, you are still keeping your class less coupled than declaring a new instance in the constructor or field.
I am trying to build an application ear file with the following structure:
app.ear
--> lib
-- app-domain.jar
-- app-api.jar
-- app-common.jar
...
--> META-INF
-- application.xml
-- glassfish-application.xml
-- MANIFEST.MF
-- app-ejb.jar
-- app-rs.war
The app-api.jar file contains my remote interfaces like
#Remote
public interface LanguageService {
/**
* #return all languages known to the system
*/
List<Language> loadLanguages();
The implementation is contained in the app-ejb.jar file and looks like this:
#Stateless
#Remote(LanguageService.class)
#Path("/language")
public class LanguageServiceImpl extends ValidatingService implements LanguageService {
#PersistenceContext(unitName = "kcalculator")
EntityManager em;
#GET
#Produces("application/json")
#Override
public List<Language> loadLanguages() {
CriteriaQuery<Language> query = createLoadLanguageQuery();
return em.createQuery(query).getResultList();
}
And finally I want to provide this as an JAX-RS web service and thus have my implementation of the javax.rs.Application class in the app-rs.war file, which looks like this:
#ApplicationPath("/resources")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(LanguageServiceImpl.class);
return s;
}
This deploys without any problem, the application class is also detected. However, when i finally access the web service an internal server error occurs due to a NPE.
The LanguageServiceImpl cannot be looked up, the log contains the following entry:
Caused by: javax.naming.NameNotFoundException: No object bound to name java:module/LanguageServiceImpl!com.kcalculator.ejb.LanguageServiceImpl
at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:741)
at com.sun.enterprise.naming.impl.GlassfishNamingManagerImpl.lookup(GlassfishNamingManagerImpl.java:715)
at com.sun.enterprise.naming.impl.JavaURLContext.lookup(JavaURLContext.java:167)
at com.sun.enterprise.naming.impl.SerialContext.lookup(SerialContext.java:471)
... 63 more
Hence the file is considered a Pojo, and so the reference to the entity manager is not initialized, which finally results in the Nullpointer exception.
I am kinda stuck, as annotating the bean class and giving it a mapped name is not working. Putting my application class into the ejb.jar file does not solve the problem either.
Can anyone point out what i am missing here?
Additional comment:
What I found out in the meantime: If I add a stateless session bean to my app-rs.war file and register it in MyApplication, it works without any problem. There injecting the LanguageService works, too. So it seems the problem is related to the fact that the service implementing bean class is located in another artifact.
The problem could be that you have an EJB with a remote interface.
JAX-RS 1.1 states in 6.2 that JAX-RS annotations only need to be supported on no-interface beans and local interfaces:
JAX-RS annotations MAY be applied to a bean’s local interface or directly to a no-interface bean.
As indicated in one of the previous comments, a working solution was found by moving the session beans to the web archive as well. Thus the separation between the ejb .jar file and the disclosing web service containing project is gone, however it seems rational to have the services in the artifact that is also supposed to provide the web services.
Thanks for the hints, however it is still not clear to me (according to the specification) why the initially described approach should not be feasible (but i realized it isn't...).
According to HK2 #Service javadoc
Annotation placed on classes that are to be automatically added to an
hk2 ServiceLocator.
I don't know how to make ServiceLocator find annotated classes automatically.
TestService
#Contract
public interface TestService {
}
TestServiceImpl
#Service
public class TestServiceImpl implements TestService {
}
Main
public static void main(String[] args) {
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
TestService service = locator.getService(TestServiceImpl.class);
System.out.println(service); // null
}
The result is always null. I have to add Descriptor so the ServiceLocator can find it.
public static void main(String[] args) {
ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
DynamicConfiguration config = dcs.createDynamicConfiguration();
config.bind(BuilderHelper.link(TestServiceImpl.class).to(TestService.class).in(Singleton.class).build());
config.commit();
TestService service = locator.getService(TestServiceImpl.class);
System.out.println(service); // TestServiceImpl instance
}
How do I let ServiceLocator find the annotated classes automatically ? Did I misunderstand something ?
You need to run the hk2-inhabitant-generator over your built classes in order to get automatic detection of services. There is more information here as well.
What that step does in the build process is to create a file named META-INF/hk2-locator/default with information about services. The createAndPopulateServiceLocator call then reads those files and automatically adds those service descriptors into the returned ServiceLocator.
FYI, I was so frustrated with the reliance on the inhabitant files rather than having the capability for runtime scanning of annotated classes, I wrote this project:
https://github.com/VA-CTT/HK2Utilities
Since Eclipse / Maven / inhabitant runtime generators wouldn't play nice, it was nearly impossible to debug code that made use of HK2 in eclipse without runtime scanning.
The HK2Utilities package is available in central:
<dependency>
<groupId>gov.va.oia</groupId>
<artifactId>HK2Utilities</artifactId>
<version>1.4.1</version>
</dependency>
To use it, you just call:
ServiceLocator locator = HK2RuntimeInitializer.init("myName", false, new String[]{"my.package.one", "my.package.two"});
This will scan the runtime classpath for classes in the packages listed, and automatically populate the service locator with them.
You don't ever have to generate inhabitant files with this model - and in practice, I found it to be faster performing than the inhabitant processing code as well (not that the performance matters much for this one-time operation)
---edit---
I still maintain this code - the current release is:
<dependency>
<groupId>net.sagebits</groupId>
<artifactId>HK2Utilities</artifactId>
<version>1.5.2</version>
</dependency>
And the project location is now:
https://github.com/darmbrust/HK2Utilities
Well now (2.6.1) all you need to do is add the dependencies - javax.inject, hk2-utils, hk2-api and hk2-metadata-generator.
When you build the project, javac compiler will generate a 'default' file in META-INF containing the wiring as follows:
[service-class-name]S
contract={contract-class-name}
This will be registered by the ServiceLocator during the run.
This should be sufficient. However if that does not work, there are other options,
mvn plugin
org.glassfish.hk2
hk2-inhabitant-generator
2.5.0-b36
generate-inhabitants
cmd line tool
java org.jvnet.hk2.generator.HabitatGenerator
[--file jarFileOrDirectory]
[--outjar jarFile]
[--locator locatorName]
[--verbose]
More on this https://javaee.github.io/hk2/inhabitant-generator.html
Currently I have a utility jar that contains a number of datastore services. Behind the scenes these datastore services use Spring Data MongoDB, and everything is configured using an app-context.xml file in the utility jar. I want this utility jar to be able to change the backing store without having to change anything that uses this utility jar.
Now, I want to create a spring mvc web application that uses the datastore services from this utility jar.
How do I set this up so that the spring mvc web app (or any other jar) can easily use the datastore services without having to know too much about the utility jar, but still have the beans in the utility jar loaded properly?
I was thinking of adding a new java bean class to the utility jar that would load the app-context in it's own jar, and then set some properties on itself for the services. Then the spring mvc would create a bean using this new class in my utility jar, and reference the services through this bean.
/**
* This bean would exist in the utility jar, and other jars/webapps would
* create a new instance of this bean.
*/
public class Services {
private MyAService myAService;
private MyBService myBService;
public Services() {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("app-context.xml");
// these are configured in the app-context.xml
this.myAService = ctx.getBean("myAService");
this.myBService = ctx.getBean("myBService");
}
}
Is this a good way to go about this? It seems like I would now have two spring application contexts, is that ok? How do I ensure that the proper app-context.xml is loaded, and not one from another jar? Is there a better way of doing this?
Since nobody has answered, I just went with my approach and it seems to work, though with a slight modification to allow the bean to destroy the internal context properly.
In your utility jar create a class that loads the app context xml like so:
public class Services implements DisposableBean {
ClassPathXmlApplicationContext ctx;
private MyAService myAService;
private MyBService myBService;
public Services() {
this.ctx = new ClassPathXmlApplicationContext("services-context.xml");
// these are configured in the services-context.xml
this.myAService = ctx.getBean("myAService");
this.myBService = ctx.getBean("myBService");
}
// Add getters for your services
#Override
public void destroy() throws Exception {
this.myAService = null;
this.myBService = null;
this.ctx.destroy();
this.ctx = null;
}
}
Make sure your "services-context.xml" file is unique on the classpath. You can do this by putting it in a folder structure that matches the package structure.
In your other jar/war, create the beaning using something like:
<bean id="services" class="Services" destroy-method="destroy"/>
Or, if your other jar/war doesn't use spring, then you do something like:
Services s = new Services();
//... use your services, then clean up when done
s.myAService.doSomething();
s.destroy();
Two approaches by which you can solve this : (Please include the dependency as part of pom.xml)
To manually include only the required utility beans into this new application-context.xml with the path referring to those class paths. That's the beauty of spring to create the selective bean only.
Have a properties file
(Include this in the new application-context.xml)
<context:property-placeholder location="WEB-INF/utility.properties"/>
<import resource="${application.path.of.utility.jar}"/>
And define path ao the utility jar
application.path.of.utility.jar=/utility/jar/path/application_context.xml
I have an elaborate Spring bean setup for integration tests. Now I'm looking into writing a Robot library to expose my test data creation / behavior execution / assertion methods to Robot tests.
However what I understand from the Robot Framework user guide is that Robot can only instantiate library classes by calling a constructor. This is a bummer because I'd rather have my instances managed by Spring.
Ideally, I'd want to be able to give Robot the path to the application context and the bean name for the library. Failing that, I'd want Robot to be able to invoke a static factory method rather than a constructor, so I'm not forced to create a new instance.
One workaround I thought of is to create the Spring context in a static initializer and wire my dependencies by fetching beans from that context.
My original class looks like:
public class MyAwesomeTests {
#Autowired
private ThisHelper thisHelper;
#Autowired
private ThatHelper thatHelper;
// implementations of test steps and such
}
So I would change the above #Autowired fields to be protected, and create a subclass that statically initializes the Spring context and defines a Robot-friendly constructor:
public class RobotFriendlyTests extends MyAwesomeTests {
private static final ApplicationContext CONTEXT = new ClassPathXmlApplicationContext(...);
public RobotFriendlyTests() {
this.thisHelper = (ThisHelper) CONTEXT.getBean("thisHelper");
this.thatHelper = (ThatHelper) CONTEXT.getBean("thatHelper");
}
}
This should work, but it feels somewhat clunky. Is there a better way I should consider? Better yet, is there a Robot extension that already does this for me?
Have you thought about using Spring #Configurable, then even instances created by a normal new will become spring managed beans.
#See Spring Reference Chapter 7.8.1 Using AspectJ to dependency inject domain objects with Spring
There's a Robot Framework extension that supports using Spring to wire test libraries, take a look at: http://code.google.com/p/robotframework-javalibcore/wiki/SpringLibrary
I am not entirely sure whether it supports your case since I am not familiar at all with Spring.