I ve been looking into CDI to simplify the code, and I ve been trying to use it with Java EE 8. I an trying to replicate an existing exemple without success. I was wondering if anyone might have experienced the same issue:
The PoolManager Class:
import javax.ejb.Startup;
import javax.ejb.Singleton;
import javax.annotation.PostConstruct;
#Singleton
#Startup
public class PoolManager {
private Queue<Object> pooledObjects;
#PostConstruct
private void init() {
System.out.println("Hi");
pooledObjects = new LinkedBlockingQueue<Object>(1_000);
for (int i = 0; i <= 1000; i++) {
pooledObjects.offer(i);
}
}
public void returnObject(Object o) {
pooledObjects.offer(o);
}
public Object borrowObject() {
return pooledObjects.poll();
}
}
the UsePoolManager Class:
public class UsePoolManager {
#Inject
private PoolManager poolManager;
public void usePooledObject() {
Object object = this.poolManager.borrowObject();
System.out.println(object);
}
}
and the Main:
public static void main(String[] args) {
UsePoolManager user = new UsePoolManager();
user.usePooledObject();
}
}
The injection doesn t seem to be working at all at runtime. I have no beans xml (i understand it is not necessary, and adding it didnt change anything.).
Any help would be greatly appreciated.
Thanks!
Checking whether I am using SE or EE for clarification...
You need to run that in JavaEE container like JBoss or Tomcat, not like standalone JavaSE application (with publis static void main)
For the sake of argumentation, using the CDI 2 container for Java SE:
in Gradle:
// https://mvnrepository.com/artifact/org.jboss.weld.se/weld-se-core
compile group: 'org.jboss.weld.se', name: 'weld-se-core', version: '3.0.4.Final'
public class CDI2Fire {
public static void main(String[] args) {
SeContainerInitializer initializer =
SeContainerInitializer.newInstance();
try (SeContainer container = initializer.disableDiscovery().addPackages(CDI2Fire.class).initialize()) {
container.select(UsePoolManager.class);
}
}
}
#ApplicationScoped
public class UsePoolManager {
#Inject
private PoolManager poolManager;
public void init(#Observes #Priority(Interceptor.Priority.APPLICATION - 100)
#Initialized(ApplicationScoped.class) Object init) throws Exception{
usePooledObject();
}
public void usePooledObject() {
Object object = this.poolManager.borrowObject();
System.out.println(object);
}
}
#Singleton
#Startup
public class PoolManager {
private Queue<Object> pooledObjects;
#PostConstruct
private void init() {
System.out.println("Hi");
pooledObjects = new LinkedBlockingQueue<Object>(1_000);
for (int i = 0; i <= 1000; i++) {
pooledObjects.offer(i);
}
}
public void returnObject(Object o) {
pooledObjects.offer(o);
}
public Object borrowObject() {
return pooledObjects.poll();
}
}
Regarding you own answer: you changed the complete application logic by moving the business method call usePooledObject() into the initialization listener instead of calling it manually as in the original example.
This is probably not the best idea, as objects which wildly run on arbitrary initialization events are very hard to control.
Thus: the point that you probably missed is, using get() after select():
try (SeContainer ...) {
// replaces the original "new":
UsePoolManager user = CDI.current().select(UsePoolManager.class).get();
user.usePooledObject();
}
Further note, that the use of CDI.current() eliminates the necessity to have a concrete container reference in scope. Thus, you can use it everywhere in your application as long as the container is active.
Related
I have a tricky situation. I am using MVP architecture for android but thats not important. I have a class called DoStandardLoginUsecase that basically just connects to a server with login info and gets a access token. i am trying to test it. But the problem is the context that i am passing in to it so i can initialize dagger.
public class DoStandardLoginUsecase extends BaseUseCase {
#Inject
UserDataRepository mUserDataRepo;
private StandardLoginInfo loginInfo;
public DoStandardLoginUsecase(Context context) {
/* SEE HERE I AM USING A APPLICATION CONTEXT THAT I PASS TO DAGGER
*/
((MyApplication)context).getPresenterComponent().inject(this);
}
#Override
public Observable<Login> buildUseCaseObservable() {
return mUserDataRepo.doStandardLogin(loginInfo);
}
public void setLoginInfo(StandardLoginInfo loginInfo) {
this.loginInfo = loginInfo;
}
}
and here is the test i have so far:
public class DoStandardLoginUsecaseTest {
DoStandardLoginUsecase standardLoginUsecase;
StandardLoginInfo fakeLoginInfo;
TestObserver<Login> subscriber;
MockContext context;
#Before
public void setUp() throws Exception {
//now when i create the object since its a mock context it will fail when it tries to call real things as these are stubs. So how do i test this object. how do i create an instance of this object ? I am willing to use [daggerMock][1] if that helps also.
standardLoginUsecase = New DoStandardLoginUsecase(context);
fakeLoginInfo = new StandardLoginInfo("fred#hotmail.com","Asdfgh4534");
subscriber = TestObserver.create();
}
#Test
public void buildUseCaseObservable(){
standardLoginUsecase.seLoginInfo(fakeLoginInfo);
standardLoginUsecase.buildUseCaseObservable().subscribe(subscriber);
subscriber.assertNoErrors();
subscriber.assertSubscribed();
subscriber.assertComplete();
}
}
I would do the test like this:
public class DoStandardLoginUsecaseTest {
private DoStandardLoginUsecase target;
private MyApplication contextMock;
#Before
public void beforeEach() {
contextMock = Mockito.mock(MyApplication.class);
// Note that you need to mock the getPresenterComponent
// but I don't know what it returns.
target = new DoStandardLoginUsecase(contextMock);
}
#Test
public void buildUseCaseObservable() {
UserDataRepository userDataMock = Mockito.mock(UserDataRepository.class);
StandardLoginInfo loginInfoMock = Mockito.mock(StandardLoginInfo.class);
target.mUserDataRepo = userDataMock;
target.setLoginInfo(loginInfoMock);
Observable<Login> expected = // create your expected test data however you like...
Mockito.when(userDataMock.doStandardLogin(loginInfoMock)).thenReturn(expected);
Observable<Login> actual = target.buildUseCaseObservable();
Assert.areSame(actual, expected);
}
}
Context
I develop, for my company a software that classifies phishing and malware containing website thanks to multiple feature extraction algorithm.
Once features are extracted we use a pool of empirical and machine learning classifiers. We choose among them thanks to election function of our own.
the code
Basically we have our classifier classes that implement the AnalysisFunction contract.
public abstract class AnalysisFunction {
abstract public StatusType analyze(List<TokenEntity> tokens);
abstract public double getPhishingProbability(List<TokenEntity> tokens);
}
Our pool of classifier is contained by a "pool" that implements AnalysisFunction.
public class PoolAnalysisFunction extends AnalysisFunction{
private final List<AnalysisFunction> candidates;
private final ChoiceFunction choice;
private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);
public PoolAnalysisFunction(List<AnalysisFunction> candidates, ChoiceFunction choice) {
this.candidates = candidates;
this.choice = choice;
}
#Override
public StatusType analyze(List<TokenEntity> tokens) {
try {
return choice.chooseAmong(candidates, tokens).analyze(tokens);
} catch (ImpossibleChoiceException e){
LOG.fatal("Not enough analysis function.", e);
return StatusType.CLEAN;
}
}
#Override
public double getPhishingProbability(List<TokenEntity> tokens) {
try {
return choice.chooseAmong(candidates, tokens).getPhishingProbability(tokens);
} catch (ImpossibleChoiceException e){
LOG.fatal("Not enough analysis function.", e);
return 0;
}
}
}
To ease the deployment and testing of new function, we want to make our pool fully customizable and instanciate every function by its name. To achieve this purpose we have a key in our property file that is like analysis.pool.functions=com.vadesecure.analysis.empirical.Function1,com.vadesecure.analysis.machine.AutomaticClassifier1.
I want to instantiate my functions thanks to that.
My problem is that those classifiers depend on different things such as custom configuration object and machine learning model.
I would like to inject those dependencies that are already bound in my hk2 injector.
import org.glassfish.hk2.api.Factory;
public class PoolFunctionFactory implements Factory<AnalysisFunction> {
private final PoolAnalysisParameters parameters;
private static final Logger LOG = LogManager.getLogger(PoolAnalysisFunction.class);
#Inject
public PoolFunctionFactory(PoolAnalysisParameters parameters) {
this.parameters = parameters;
}
#Override
public AnalysisFunction provide() {
try {
Class<?> choice = Class.forName(parameters.getChoiceFunctionFQDN());
ChoiceFunction choiceFunction = new PhishingPriorityChoiceFunction(); // default choice
if(choice.getSuperclass().isInstance(ChoiceFunction.class)){
choiceFunction = (ChoiceFunction) choice.newInstance();
}
List<AnalysisFunction> analysisFunctions = new LinkedList<>();
// I want to instantiate here
}
return new PoolAnalysisFunction(analysisFunctions, choiceFunction);
} catch (ClassNotFoundException|IllegalAccessException|InstantiationException e){
LOG.fatal(e, e);
}
return null;
}
#Override
public void dispose(AnalysisFunction analysisFunction) {
LOG.trace(String.format("%s end of life", analysisFunction));
}
}
On example of model-dependant classifier is :
public class SVMF2AnalysisFunction extends AnalysisFunction {
private final SVMContainer modelContainer;
private double probability = 0.0;
private double threshold = 0.9;
#Inject // i build this model in a parallel thread
public SVMF2AnalysisFunction(SVMContainer modelContainer) {
this.modelContainer = modelContainer;
}
#Override
public StatusType analyze(List<TokenEntity> tokens) {
if (modelContainer.getModel() == null) {
return null;
}
probability = modelContainer.getModel().analyse(tokens.stream());
return probability >= threshold ? StatusType.PHISHING : StatusType.CLEAN;
}
#Override
public double getPhishingProbability(List<TokenEntity> tokens) {
return probability;
}
}
How can I achieve those instanciations.
My first approach was to inject the serviceLocator but i found no documentations for doing this and a colleague said me it was not good.
He told be to document myself about proxies but it doesn't seem to be a good thing for me or perhaps I missed something.
You could just configure all this in your binder. This way you don't need to worry about trying to instantiate everything yourself. Just let HK2 do all the work
#Override
protected void configure() {
bindAsContract(PoolAnalysisFunction.class).in(Singleton.class);
bind(choiceFnClass).to(ChoiceFunction.class);
for (Class<AnalysisFunction> analysisFnClass: analyisFnClasses) {
bind(analysisFnClass).to(AnalysisFunction.class).in(Singleton.class);
}
}
Then you can just inject everything into the PoolAnalysisFunction class, without the need to use a factory.
#Inject
public PoolAnalysisFunction(IterableProvider<AnalysisFunction> candidates,
ChoiceFunction choice) {
this.choice = choice;
this.candidates = new ArrayList<>();
candidates.forEach(this.candidates::add);
}
Notice the IterableProvider class. This is an HK2 class for injecting multiple services bound to the same contract.
Or if you want to use the factory, you could, and just inject the functions into the factory. That way you can make the PoolAnalysisFunction class independent of an HK2 classes (i.e. the InjectableProvider).
again a small problem by understanding "how tapestry works".
I've got a Tapestry component (in this case a value encoder):
public class EditionEncoder implements ValueEncoder<Edition>, ValueEncoderFactory<Edition> {
#Inject
private IEditionManager editionDao;
public EditionEncoder(IEditionManager editionDao) {
this.editionManager = editionDao;
}
#Override
public String toClient(Edition value) {
if(value == null) {
return "";
}
return value.getName();
}
#Override
public Edition toValue(String clientValue) {
if(clientValue.equals("")) {
return null;
}
return editionManager.getEditionByName(clientValue);
}
#Override
public ValueEncoder<Edition> create(Class<Edition> type) {
return this;
}
}
Injecting the the Manager is not working, because the Encoder is created within a page like that:
public void create() {
editionEncoder = new EditionEncoder();
}
casued by this, i'm forced to use this ugly solution:
#Inject
private IEditionManager editionmanager;
editionEncoder = new EditionEncoder(editionManager);
Is there a better way to inject components during runtime or is there a better solution in general for it?
Thanks for your help in advance,
As soon as you use "new" then tapestry-ioc is not involved in object creation and can't inject. You should inject everything and never use "new" for singleton services. This is true for all ioc containers, not just tapestry-ioc.
Also if you put #Inject on a field then you don't also need a constructor to set it. Do one or the other, never both.
You should do something like this:
public class MyAppModule {
public void bind(ServiceBinder binder) {
binder.bind(EditionEncoder.class);
}
}
Then in your page/component/service
#Inject EditionEncoder editionEncoder;
If you wanted to put your own instantiated objects in there you can do
public class MyServiceModule {
public void bind(ServiceBinder binder) {
binder.bind(Service1.class, Service1Impl.class);
binder.bind(Service2.class, Service2Impl.class);
}
public SomeService buildSomeService(Service1 service1, Service2 service2, #AutoBuild Service3Impl service3) {
Date someDate = new Date();
return new SomeServiceImpl(service1, service2, service3, someDate);
}
}
Let's say I have a class called Server, and I would like to allow others to write Plugins for it. Say Plugin is an Interface that extends Runnable and adds a single method: void init(...). It is the job of a plugin to collect data and send it to the server. When the time comes to send data to the server, however, how does it do this? Coming from C and C++ I am looking for a thinking along the lines of a function pointer. It seems to be possible in Java though I have not found examples outside the Java Standard Class Library.
How do I pass a method reference to the init method such that it can be stored by the Plugin, and then how do I invoke the method whenever the Plugin wants to send data? For now say that the desired Server method is: void sendData(Integer data).
For example:
// Inside Server
Plugin p = new PluginImplementation();
p.init(this::sendData);
// Plugin init
public void init(?? sendMethod) {
storedSendMethod = sendMethod;
// ...
}
// Plugin run
public void run() {
// ...
storedSendMethod(x) // Sends data to server
// ...
}
Using java.util.function.Function we can pass a function as an argument to a method, and then use apply() to apply it to the relevant arguments. Here's an example:
import java.util.function.Function;
public class FunctionDemo {
// we will pass a reference to this method
public static Integer square(Integer x) {
return x * x;
}
// this method accepts the function as an argument and applies it to the input: 5
public static Integer doSomething(Function<Integer, Integer> func) {
return func.apply(5);
}
public static void main(String[] args) {
// and here's how to use it
System.out.println(doSomething(FunctionDemo::square)); // prints 25
}
}
Additional version with multiple parameters (passed as an array):
public static Integer sum(Integer[] x) {
Integer result = 0;
for(int i = 0; i < x.length; i++)
result += x[i];
return result;
}
public static void main(String[] args) {
Integer[] arr = {1,2,3,4,5};
System.out.println(doSomething(Play::sum, arr));
}
public static Integer doSomething(Function<Integer[], Integer> func,
Integer[] arr) {
return func.apply(arr);
}
If the method is void sendData(Integer data) that corresponds to a consumer that takes an Integer and returns a void which is covered by the built in Consumer<Integer> interface which has an accept(Integer) method that will invoke your function when called.
So your code will look like this:
public void init(Consumer<Integer> sendMethod) {
storedSendMethod = sendMethod;
// ...
}
// Plugin run
void run() {
// ...
storedSendMethod.accept(x) // Sends data to server
// ...
}
As a sidenote, having an init method is probably a bad Java design. you are better moving the initialization to the constructor if possbile
Plugin p = new PluginImplementation( this::sendData);
In java, you do it with a callback,
This is your callback interface,
public interface SendCallback {
public void doSend(Object toSend);
}
This is the plugin interface, All plugin must implement this interface
public interface Plugin extends Runnable {
public void init(SendCallback callback);
}
This is the Server's code.
public class Server {
Plugin plugin;
SendCallback callback = new SendCallback() {
public void doSend(Object toSend) {
// logic to send object 'toSend'
}
}
public Server() {
plugin = new MyPlugin();
plugin.init(callback);
}
}
This is your plugin implementation.
public class MyPlugin implements Plugin {
SendCallback callback = null;
Object x = null;
public void init(SendCallback callback) {
this.callback = callback;
}
public void run() {
x = "Somthing"; // initialize the x object
callback.doSend(x);
}
}
You will notice, the server define the callback implementation.
The plugin will invoke the callback's method doSend.
I hope, this helps
There is method reference in Java 8, however you can just pass a whole object and call its sendData() method. In a 'plug-in' situation, using interfaces for each helps the plugin and the server have 'looser' coupling.
public interface Server {
void setData(...);
}
public class MyPlugin implements plugin {
private Server server;
void init(Server s ) {
this.server = s;
}
void run() {
...
this.server.setData(...);
...
}
}
interface Server{
...
void sendData(String message);
}
Plugin doesn't need a function reference, you can use the Server interface for informing Plugin to know about that method.
class PluginX implements Plugin{
...
private Server server;
void init(Server server) {
this.server = server;
}
public void run() {
// ...
server.sendData(x) // Sends data to server
// ...
}
}
I have a Singleton/Factory object that I'd like to write a JUnit test for. The Factory method decides which implementing class to instantiate based upon a classname in a properties file on the classpath. If no properties file is found, or the properties file does not contain the classname key, then the class will instantiate a default implementing class.
Since the factory keeps a static instance of the Singleton to use once it has been instantiated, to be able to test the "failover" logic in the Factory method I would need to run each test method in a different classloader.
Is there any way with JUnit (or with another unit testing package) to do this?
edit: here is some of the Factory code that is in use:
private static MyClass myClassImpl = instantiateMyClass();
private static MyClass instantiateMyClass() {
MyClass newMyClass = null;
String className = null;
try {
Properties props = getProperties();
className = props.getProperty(PROPERTY_CLASSNAME_KEY);
if (className == null) {
log.warn("instantiateMyClass: Property [" + PROPERTY_CLASSNAME_KEY
+ "] not found in properties, using default MyClass class [" + DEFAULT_CLASSNAME + "]");
className = DEFAULT_CLASSNAME;
}
Class MyClassClass = Class.forName(className);
Object MyClassObj = MyClassClass.newInstance();
if (MyClassObj instanceof MyClass) {
newMyClass = (MyClass) MyClassObj;
}
}
catch (...) {
...
}
return newMyClass;
}
private static Properties getProperties() throws IOException {
Properties props = new Properties();
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(PROPERTIES_FILENAME);
if (stream != null) {
props.load(stream);
}
else {
log.error("getProperties: could not load properties file [" + PROPERTIES_FILENAME + "] from classpath, file not found");
}
return props;
}
This question might be old but since this was the nearest answer I found when I had this problem I though I'd describe my solution.
Using JUnit 4
Split your tests up so that there is one test method per class (this solution only changes classloaders between classes, not between methods as the parent runner gathers all the methods once per class)
Add the #RunWith(SeparateClassloaderTestRunner.class) annotation to your test classes.
Create the SeparateClassloaderTestRunner to look like this:
public class SeparateClassloaderTestRunner extends BlockJUnit4ClassRunner {
public SeparateClassloaderTestRunner(Class<?> clazz) throws InitializationError {
super(getFromTestClassloader(clazz));
}
private static Class<?> getFromTestClassloader(Class<?> clazz) throws InitializationError {
try {
ClassLoader testClassLoader = new TestClassLoader();
return Class.forName(clazz.getName(), true, testClassLoader);
} catch (ClassNotFoundException e) {
throw new InitializationError(e);
}
}
public static class TestClassLoader extends URLClassLoader {
public TestClassLoader() {
super(((URLClassLoader)getSystemClassLoader()).getURLs());
}
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.startsWith("org.mypackages.")) {
return super.findClass(name);
}
return super.loadClass(name);
}
}
}
Note I had to do this to test code running in a legacy framework which I couldn't change. Given the choice I'd reduce the use of statics and/or put test hooks in to allow the system to be reset. It may not be pretty but it allows me to test an awful lot of code that would be difficult otherwise.
Also this solution breaks anything else that relies on classloading tricks such as Mockito.
When I run into these sort of situations I prefer to use what is a bit of a hack. I might instead expose a protected method such as reinitialize(), then invoke this from the test to effectively set the factory back to its initial state. This method only exists for the test cases, and I document it as such.
It is a bit of a hack, but it's a lot easier than other options and you won't need a 3rd party lib to do it (though if you prefer a cleaner solution, there probably are some kind of 3rd party tools out there you could use).
You can use Reflection to set myClassImpl by calling instantiateMyClass() again. Take a look at this answer to see example patterns for playing around with private methods and variables.
If executing Junit via the Ant task you can set fork=true to execute every class of tests in it's own JVM. Also put each test method in its own class and they will each load and initialise their own version of MyClass. It's extreme but very effective.
Below you can find a sample that does not need a separate JUnit test runner and works also with classloading tricks such as Mockito.
package com.mycompany.app;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import java.net.URLClassLoader;
import org.junit.Test;
public class ApplicationInSeparateClassLoaderTest {
#Test
public void testApplicationInSeparateClassLoader1() throws Exception {
testApplicationInSeparateClassLoader();
}
#Test
public void testApplicationInSeparateClassLoader2() throws Exception {
testApplicationInSeparateClassLoader();
}
private void testApplicationInSeparateClassLoader() throws Exception {
//run application code in separate class loader in order to isolate static state between test runs
Runnable runnable = mock(Runnable.class);
//set up your mock object expectations here, if needed
InterfaceToApplicationDependentCode tester = makeCodeToRunInSeparateClassLoader(
"com.mycompany.app", InterfaceToApplicationDependentCode.class, CodeToRunInApplicationClassLoader.class);
//if you want to try the code without class loader isolation, comment out above line and comment in the line below
//CodeToRunInApplicationClassLoader tester = new CodeToRunInApplicationClassLoaderImpl();
tester.testTheCode(runnable);
verify(runnable).run();
assertEquals("should be one invocation!", 1, tester.getNumOfInvocations());
}
/**
* Create a new class loader for loading application-dependent code and return an instance of that.
*/
#SuppressWarnings("unchecked")
private <I, T> I makeCodeToRunInSeparateClassLoader(
String packageName, Class<I> testCodeInterfaceClass, Class<T> testCodeImplClass) throws Exception {
TestApplicationClassLoader cl = new TestApplicationClassLoader(
packageName, getClass(), testCodeInterfaceClass);
Class<?> testerClass = cl.loadClass(testCodeImplClass.getName());
return (I) testerClass.newInstance();
}
/**
* Bridge interface, implemented by code that should be run in application class loader.
* This interface is loaded by the same class loader as the unit test class, so
* we can call the application-dependent code without need for reflection.
*/
public static interface InterfaceToApplicationDependentCode {
void testTheCode(Runnable run);
int getNumOfInvocations();
}
/**
* Test-specific code to call application-dependent code. This class is loaded by
* the same class loader as the application code.
*/
public static class CodeToRunInApplicationClassLoader implements InterfaceToApplicationDependentCode {
private static int numOfInvocations = 0;
#Override
public void testTheCode(Runnable runnable) {
numOfInvocations++;
runnable.run();
}
#Override
public int getNumOfInvocations() {
return numOfInvocations;
}
}
/**
* Loads application classes in separate class loader from test classes.
*/
private static class TestApplicationClassLoader extends URLClassLoader {
private final String appPackage;
private final String mainTestClassName;
private final String[] testSupportClassNames;
public TestApplicationClassLoader(String appPackage, Class<?> mainTestClass, Class<?>... testSupportClasses) {
super(((URLClassLoader) getSystemClassLoader()).getURLs());
this.appPackage = appPackage;
this.mainTestClassName = mainTestClass.getName();
this.testSupportClassNames = convertClassesToStrings(testSupportClasses);
}
private String[] convertClassesToStrings(Class<?>[] classes) {
String[] results = new String[classes.length];
for (int i = 0; i < classes.length; i++) {
results[i] = classes[i].getName();
}
return results;
}
#Override
public Class<?> loadClass(String className) throws ClassNotFoundException {
if (isApplicationClass(className)) {
//look for class only in local class loader
return super.findClass(className);
}
//look for class in parent class loader first and only then in local class loader
return super.loadClass(className);
}
private boolean isApplicationClass(String className) {
if (mainTestClassName.equals(className)) {
return false;
}
for (int i = 0; i < testSupportClassNames.length; i++) {
if (testSupportClassNames[i].equals(className)) {
return false;
}
}
return className.startsWith(appPackage);
}
}
}