how the weld container service for application in java se environment? - java

I am a novice in weld, and through several days exploration but I only know some fundamental concept of weld.
I'm intended to use weld container in java se environment. And follw What is the easiest way to have CDI and JPA in Java SE? my code segment is below:
public class SayHello {
public SayHello(){}
public void sayHello(){
System.out.println("Hello");
}
}
import javax.inject.Inject;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
public class UseInject {
private SayHello obj;
public UseInject(){}
#Inject
public UseInject(SayHello obj){
this.obj = obj;
}
public void show(){
obj.sayHello();
}
public static void main(String[] args){
Weld weld = new Weld();
WeldContainer container = weld.initialize();
UseInject ui = container.instance().select(UseInject.class).get();
ui.show();
weld.shutdown();
}
}
and my application is based on maven. Here is the jar dependency segment in pom.xml
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>3.0.0.Alpha17</version>
my intention is inject SayHello object into UseInject Object so the final output of this application is "Hello".
But things are not so smooth, the jvm report the follow error:
and through search from internet,there is a saying that build a empty beans.xml is ok, and I follow it can't make effect. And as for the main method I imitate What is the easiest way to have CDI and JPA in Java SE? I don't know what thing it do, and What is the easiest way to have CDI and JPA in Java SE? use the #Produces annotation, I don't know whether I should use it too. And I had intended use it for the SayHello Class, but I don't know which jar should I import in order to use it,so I give up.
Now I want to:
1. know how the weld service for se application in other words what things the main method does?
2. How can I run my application successfully using weld?
3. when we should use the annotation #Produces
And I made reference to a number of relevant issues e.g.weld and java seHow to bootstrap weld-se in a JUnit testetc. but find they are all to senior for me.
thanks for your attention advance.

How can I run my application successfully using weld?
The error message is telling you that you have to create a file named beans.xml under the directory META-INF. So to solve the problem just do the following:
Directory named META-INF under src/main/resources directory
Create an empty file named beans.xml under META-INF so that your project is CDI enabled.
when we should use the annotation #Produces
You use this annotation if you want to use any Java primitive types such as Integer, String, ... as CDI beans, or any type / class in an external library which does not contain the META-INF/beans.xml file in the classpath.
Example:
public class SayHello {
#Produces
private double pi = 3.14159;
// the rest of the code
}
and you can inject the value of PI in another place in your code as:
public class UseInject {
#Inject
private double pi; // 3.14159 will be injected here
// the rest of the code
public static void main(...) {
// ....
UseInject ui = container.instance().select(UseInject.class).get();
ui.show();
System.out.println(ui.pi);
// ...
}
The value 3.14159 should be displayed on the console.

Related

How to provide components from a library, for consumption by multiple DI frameworks

My team owns a library that provides components that must be referencable by code that consumes the library. Some of our consumers use Spring to instantiate their apps; others use Guice. We'd like some feedback on best-practices on how to provide these components. Two options that present themselves are:
Have our library provide a Spring Configuration that consumers can #Import, and a Guice Module that they can install.
Have our library provide a ComponentProvider singleton, which provides methods to fetch the relevant components the library provides.
Quick sketches of what these would look like:
Present in both approaches
// In their code
#AllArgsConstructor(onConstructor = #__(#Inject))
public class ConsumingClass {
private final FooDependency foo;
...
}
First approach
// In our code
#Configuration
public class LibraryConfiguration {
#Bean public FooDependency foo() {...}
...
}
---
public class LibraryModule extends AbstractModule {
#Provides FooDependency foo() {...}
...
}
========================
========================
// In their code
#Configuration
#Import(LibraryConfiguration.java)
public class ConsumerConfiguration {
// Whatever initiation logic they want - but, crucially, does
// *not* need to define a FooDependency
...
}
---
// *OR*
public class ConsumerModule extends AbstractModule {
#Override
public void configure() {
// Or, simply specify LibraryModule when creating the injector
install(new LibraryModule());
...
// As above, no requirement to define a FooDependency
}
}
Second approach
// In our code
public class LibraryProvider {
public static final INSTANCE = buildInstance();
private static LibraryProvider buildInstance() {...}
private static LibraryProvider getInstance() {return INSTANCE;}
}
========================
========================
// In their code
#Configuration
public class ConsumerConfiguration {
#Bean public FooDependency foo() {
return LibraryProvider.getInstance().getFoo();
}
...
}
// or equivalent for Guice
Is there an accepted Best Practice for this situation? If not, what are some pros and cons of each, or of another option I haven't yet thought of? The first approach has the advantage that consumers don't need to write any code to initialize dependencies, and that DI frameworks can override dependencies (e.g. with mocked dependencies for testing); whereas the second approach has the advantage of being DI-framework agnostic (if a new consumer wanted to use Dagger to instantiate their app, for instance, we wouldn't need to change the library at all)
I think the first option is better. If your library has inter-dependencies between beans then the code of #Configuration in case of spring in the second approach) will be:
Fragile (what if application doesn't know that a certain bean should be created)
Duplicated - this code will appear in each and every consumer's module
When the new version of your library gets released and a consumer wants to upgrade- there might be changes in consumer's configuration ( the lib might expose a new bean, deprecate or even remove some old stuff, etc.)
One small suggestion:
You can use Spring factories and then you don't even need to make an #Import in case of spring boot. just add a maven dependency and it will load the configuration automatically.
Now, make sure that you work correctly with dependencies in case of that approach.
Since you code will include both spring and Juice dependent code, you'll add dependencies on both for your maven/gradle module of the library. This means, that consumer that uses, say, guice, will get all the spring stuff because of your library. There are many ways to overcome this issue depending on the build system of your choice, just want wanted to bring it up

Testing Jersey app, Injecting classes using Jersey Injection built-in framework (HK2)

I need to create tests for some class. This class in main project (src/main/java/..) is injected easily into another classes, since I have custom ResourceConfig class which declares which packages have to be scanned to seek for service classes.
Now I created test directories (in src/test/java/..) and created a class, something like:
public class TheMentionedClassIntegrationTest {
#Inject
private TheMentionedClass theMentionedClass ;
#Test
public void testProcessMethod() {
assertNotNull(theMentionedClass);
}
}
But the problem is that whatever I do the class is always null. In another tests in the project I was using JerseyTest class. So I tried to do the same here, extend TheMentionedClassIntegrationTest with JerseyTest, override configure method, create my private ResourceConfig class which registers Binder (default for whole project) and register TheMentionedClassIntegrationTest as well.
It didnt work. I did many different attempts but none of them were successfull. I think working with HK2 is extremly difficult, there is no good documentation or so..
Do you guys have an idea how to inject TheMentionedClass into the test class? Maybe my approach is wrong?
Thanks!
The easiest thing to do is to just create the ServiceLocator and use it to inject the test class, as see here. For example
public class TheMentionedClassIntegrationTest {
#Inject
private TheMentionedClass theMentionedClass;
#Before
public void setUp() {
ServiceLocator locator = ServiceLocatorUtilities.bind(new YourBinder());
locator.inject(this);
}
#Test
public void testProcessMethod() {
assertNotNull(theMentionedClass);
}
}
You could alternatively use (make) a JUnit runner, as seen here.
For some other ideas, you might want to check out the tests for the hk2-testing, and all of its containing projects for some use case examples.

Java reflection instance with Weld-SE context

I have a problem with creating object via reflection with Weld context.
I'm loading classes and their configuration from external files.
Simplify my code looks like:
final Class<?> moduleClass = Class.forName(properties.getProperty("className"));
then I'm creating instance of this class
final Constructor<?> constructor = moduleClass.getDeclaredConstructor();
module = (Module) constructor.newInstance();
Module class:
#ModuleImpl
public class ExampleModule extends AbstractModule (implements Module interface) {
#Inject
private Test test;
Module is created sucessfully, but it hasn't weld context to inject Test class. And I cannot find the correct way. I tried to make own producer but I'm not much familiar with Weld and CDI in Java SE yet.
My broken producer (I think that its totaly bad)
public class InjectionProvider {
#Produces
public Module getInsrance(Class<?> clazz) throws ReflectiveOperationException {
final Constructor<?> constructor = clazz.getDeclaredConstructor();
return (Module) constructor.newInstance();
}
}
I cannot find something about this problem, so if anyone can help me I will be glad. I really need this way of creating classes because I don't want to change my code everytime when I need change some property in Module classes.
EDITED:
I cannot make it with producers. But I found a workaround. I'm not sure if is it good solution but it works for now.
I created a singleton class with Weld context.
public class TheMightyWeld {
private static Weld weld;
private static WeldContainer weldContainer;
public static WeldContainer getThePowerOfCreation() {
if (weldContainer == null) {
weld = new Weld();
weldContainer = weld.initialize();
}
return weldContainer;
}
public static void shutdown() {
if (weld != null) {
weld.shutdown();
}
}
}
And then I can initialize my app with
TheMightyWeld.getPowerOfCreation().instance().select(FXApplicationStarter.class).get().startApplication(primaryStage, getParameters());
And later in code I can reuse it for reflection
module = (Module) TheMightyWeld.getPowerOfCreation().instance().select(moduleClass).get();
EDITED 2:
I found better a solution. I can inject weld Instance
#Inject
private Instance<Object> creator;
then I can do only this
creator.select(moduleClass).get();
I think that this is a good solution.
I don't know if I understand your question right,
specifically the part related to the class loading
vs. the code used in the producer.
I am wondering if you expect inject to work for
a object that you instanciate for yourself through
Class.forName. As the decoration of objects
through frameworks usually is done
using a modified classloader and returning
the modified or decorated object, I guess your
approach disables this decoration (dependency injection).
You not using a call to new leaving the instanciating
to the classloader rather you are using a instantiation
through reflection.
See edited post. If someone have a better solution I will be glad for it.

Application-wide configuration of Lambdaj FinalClassArgumentCreators. Where and how to do it?

We have a problem with configuring lambdaj to work with Joda Time. Since LocalDate is a final class, Lambdaj needs to be initialized like following: (see bug 70)
public class LocalDateArgumentCreator implements FinalClassArgumentCreator<LocalDate> {
private final long MSECS_IN_DAY = 1000L * 60L * 60L * 24L;
public LocalDate createArgumentPlaceHolder(int seed) {
return new LocalDate((long)seed * MSECS_IN_DAY);
}
}
ArgumentsFactory.registerFinalClassArgumentCreator(LocalDate.class, new LocalDateArgumentCreator());
Since we need this configuration to be applied virtually everywhere, we are short of options on how to implement this. Our application is a web application based on Spring and Wicket.
I have come up with three different options:
1. Static initialization block in the core maven module
Since the core module is included in every other module, all modules would include the class. The remaining question is that do static blocks always get initialized even if there are no references to the target class?
Example
public final class LambdajInitializer {
static {
// initialize like above
}
}
2. An initializing bean in applicationContext.xml
Downside: never gets initialized for non-Spring tests
Example: In applicationContext-core.xml (included in every module)
<bean class="...LambdajInitializer" />
public class LambdajInitializer {
#PostConstruct
public void init() {
// Lambdaj initialization
}
}
3. A call to a initializing method in the Wicket application class
Downside: never gets initialized outside the web module
public class MyApplication extends WebApplication {
#Override
public void init() {
...
// Lambdaj initialization
...
}
}
My question is: which is the preferable way to achieve this?
I would avoid static initialization as you may have (how unlikely is your call) modules in future which won't need this kind of initialization. I do not fancy static inits.
It is a reasonable approach, you can place this initialization in a #Before section of your non-spring unit tests
Like for 2., you can initialize the code in your #Before sections.
Option 4. you could create a test-only Spring configuration class/file and pass it on to your tests using #ContextConfiguration
We came to the following conclusion:
For the runtime of the application, we initialize the Lambdaj's FinalClassArgumentCreators in the Wicket Application class's init() method. This way, they are almost certainly being initialized before any Lambdaj usage.
For testing of Wicket components and pages, we created our own TestApplication class, which uses the same initialization code as the production application.
For out standalone batch jobs, we decided not to use Lambdaj. If we later on decide to use it, we will probably extract the initialization to a class that Spring would instantiate.

Inject inaccessible properties using Guice

How can I inject a property to a class I don't have access to using Guice? I only have access to the .jar that contains that class.
Also, I need the injected property to be available from the start of a Web Application (I suppose I can do this with a Servlet though).
Thanks
Take a look at the Provider class. You can have something like this (where Foo is the 3rd party bean):
public class FooProvider implements Provider<Foo> {
public Foo get() {
return new Foo();
}
}
(Alternatively, take a look at guice-xml, but I don't know how stable and up-to-date it is.)

Categories