Java : Dependency Injection by introspection, recursion and annotation - java

So the idea behind this is that I have a main class that is starting a Server (servlet) and I want to inject all the classes that servlet will need in the future so it doesn't instantiate them himself (considered bad practice ?)
I create an annotation ToInject to indicate the attributes within classes that will need to be injected for the whole system to work.
I call my injectionService right before I instantiate the servlet : InjectionService.injectObject(ServletMain.class) and my hope is that with the recursion it will instantiate and place the right objects at the right places.
I'm using a HashMap to keep the instances of each type of object I iterate over.
In my ServletMain class : instead of writing LoginController log = new LoginController(); I would write #ToInject LoginController log; .
Is this the right way to go ? It doesn't work right now but I can't see what I'm missing.
Edit/PS : the reason why I'm not using Spring-like tools is because the assignment doesn't allow us to use those.
I realize this is a very specific question, thank you in advance for the answers.
package utils;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import domain.factory.IFactory;
public class InjectionService {
private static IFactory factory = null;
private static HashMap<Object, Object> map_class_instance = new HashMap<Object, Object>();
public static void injectObject(Object o) throws NoSuchMethodException, SecurityException,
ClassNotFoundException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
Field[] fields = o.getClass().getDeclaredFields();
for (Field f : fields) {
if (f.isAnnotationPresent(ToInject.class)) {
if (map_class_instance.get(o) == null) {
Constructor cons = (Constructor) Class.forName((String) o).getDeclaredConstructor();
cons.setAccessible(true);
Object obj = cons.newInstance();
map_class_instance.put(o.getClass(), obj);
// recursif
f.set(o, map_class_instance.get(f));
injectObject(f);
}
f.set(o, map_class_instance.get(f));
injectObject(f);
}
}
}

Related

PowerMock won't mock static method to throw an Exception in a Spring-Boot application

I realize there are many many very similar questions. I've been through all of them and I still cannot make my code work.
I have a service defined in my Spring-Boot application, just like this:
#Service
public class FileStorageService {
private final Path fileStorageLocation;
#Autowired
public FileStorageService(final FileStorageProperties fileStorageProperties) {
//FileStorageProperties is a very simple class that right now just holds one String value
this.fileStorageLocation = Paths.get(fileStorageProperties.getUploadDir())
.toAbsolutePath()
.normalize();
try {
Files.createDirectories(fileStorageLocation);
} catch (IOException e) {
// FileStorageException is my custom, runtime exception
throw new FileStorageException("Failed to create directory for stored files", e);
}
}
}
And I want to test scenario, when directory creation fails and thus I need to mock method Files.createDirectories(). My test class looks like this:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.IOException;
import java.nio.file.Files;
#RunWith(PowerMockRunner.class)
#PrepareForTest({Files.class})
public class FileStorageServiceTest {
private static final String UPLOAD_DIR = "uploadDir";
#Test(expected = FileStorageException.class)
public void some_test() throws IOException {
PowerMockito.mockStatic(Files.class);
PowerMockito.when(Files.createDirectories(Mockito.any())).thenThrow(new IOException());
new FileStorageService(createFileStorageProperties());
}
private FileStorageProperties createFileStorageProperties() {
final FileStorageProperties fileStorageProperties = new FileStorageProperties();
fileStorageProperties.setUploadDir(UPLOAD_DIR);
return fileStorageProperties;
}
}
I believe I followed every step from tutorials and questions I've read.
I use:
#RunWith(PowerMockRunner.class),
#PrepareForTest({Files.class}),
PowerMockito.mockStatic(Files.class),
and PowerMockito.when(Files.createDirectories(Mockito.any())).thenThrow(new IOException());.
Still, no exception is thrown during test and it fails. WIll be super thankful for the help, cause I feel I miss something really simple and just cannot see it.
From: https://github.com/powermock/powermock/wiki/Mock-System
Normally you would prepare the class that contains the static methods (let's call it X) you like to mock but because it's impossible for PowerMock to prepare a system class for testing so another approach has to be taken. So instead of preparing X you prepare the class that calls the static methods in X!
Basically, we mock the class's use of the System class, rather than unmockable System class itself.
#PrepareForTest({Files.class})
An alternative, non-Powermock way to do this without mocking any system class would be to create a helper method, #Spy the original class, and mock that helper method specifically to throw the exception.
when(spy.doSomethingWithSystemClasses()).thenThrow(new Exception("Foo");

Invoke of a method - logging as method declaring class

I'm currently using JBoss interceptors and Proxy classes for wrapping method invoking at runtime and log some statistics.
So said, having this code:
public class ProxyLoggingInterceptor <T> implements InvocationHandler {
private Logger logger = LoggerFactory.getLogger(ProxyLoggingInterceptor.class);
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
logger.info("%s.%s", t.getClass().getSimpleName(), method.getName());
}
}
the log will produce something like this:
12-11-2018 11:41.09,728 INFO (ProxyLoggingInterceptor) - [ANALYTICS]: MyClass.myMethod
However I'd like to show the logging declaring class as the logger entry, that is MyClass.
The desired result would be like:
12-11-2018 11:41.09,728 INFO (MyClass) - [ANALYTICS]: MyClass.myMethod
Is there any way that would not considered as a bad practice ?
Actually I am not into AOP based on dynamic proxies, I always use AspectJ where this kind of problem does not exist and it is easy to get the information you want because the original classes get modified. But having found the question anyway due to its aop tag and having played around a bit, I am trying to answer it:
package de.scrum_master.app;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.function.Function;
public class ProxyLoggingInterceptor<T> implements InvocationHandler {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.printf(
"%s.%s%n",
proxy.getClass().getGenericInterfaces()[0].getTypeName(),
method.getName()
);
return null;
}
public static void main(String[] args) {
ClassLoader classLoader = ProxyLoggingInterceptor.class.getClassLoader();
Map mapProxy = (Map) Proxy.newProxyInstance(
classLoader,
new Class[] { Map.class },
new ProxyLoggingInterceptor<Map>()
);
mapProxy.put("foo", 11);
Function functionProxy = (Function) Proxy.newProxyInstance(
classLoader,
new Class[] { Function.class },
new ProxyLoggingInterceptor<Function>()
);
functionProxy.apply("x");
Runnable runnableProxy = (Runnable) Proxy.newProxyInstance(
classLoader,
new Class[] { Runnable.class },
new ProxyLoggingInterceptor<Runnable>()
);
runnableProxy.run();
}
}
Console output:
java.util.Map.put
java.util.function.Function.apply
java.lang.Runnable.run
Is that what you want?

How to avoid internal Nashorn classes in implementations of JSObject

I want to provide my own implementation of JSObject as described here: https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions
JSObject is within the jdk.nashorn.api package. Unfortunately the classes of the objects you get in the api-methods are not. You get NativeArray and JO4, which are both part of the internal package. My question is, how should I handle such objects? Is it recommended to use the internal functions? Or is it possible to cast those objects to anything in the api-package?
Here is my simple example:
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import jdk.nashorn.api.scripting.AbstractJSObject;
public class JacksonToJSObject extends AbstractJSObject {
final static ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
public static void main(String[] args) throws ScriptException, NoSuchMethodException {
String script = "var fun = function(obj) {obj.arrayField = [1,2]; obj.objField = {\"field\":\"test\"}};";
engine.eval(script);
((Invocable)engine).invokeFunction("fun", new JacksonToJSObject());
}
#Override
public void setMember(String name, Object value) {
System.out.println(value.getClass().getCanonicalName());
}
}
This is the output
jdk.nashorn.internal.objects.NativeArray
jdk.nashorn.internal.scripts.JO4
I've filed a bug against JDK https://bugs.openjdk.java.net/browse/JDK-8137258 to automatically handle the wrapping. In the meanwhile, please use the workaround suggested by Attila Szegedi.
I think we should wrap these automatically for you. In the meantime, you can pass these internal objects to jdk.nashorn.api.scripting.ScriptUtils.wrap(Object) yourself to get back a JSObject. This method is idempotent if you pass it something that's already wrapped, so this solution won't break if we fix the wrapping.

How can I pass parameters to a jar, whilst using a ClassLoader?

Here's my code
package serverloader;
import java.net.URL;
import java.net.URLClassLoader;
public class ServerLoader {
public void initiate(String[] arguments) throws Exception {
System.out.println("Initiating...");
URL link = new URL("link");
URLClassLoader classLoader = new URLClassLoader(new URL[]{link});
Object o = classLoader.loadClass("class.MyClass").newInstance();
System.out.println("Loaded, starting...");
}
}
This is the loader to load my actual application, but for some reason it's not starting up and I believe it's because there are parameters that are needed to launch the application that's being loaded here, so how do I pass the parameters, which are here
String[] arguments
to the jar that is being loaded by the ClassLoader?
Kind of, you need to use reflection to get the constructor which meets your needs, something like...
Class[] clazz = classLoader.loadClass("class.MyClass");
Constructor constructor = clazz.getConstructor(String[].class);
Once you have the constructor, you can create a new instance of the class using Constructor#newInstance...
Object o = constructor.newInstance(arguments);
As an example...

How to set values to a class variables without using setters

I want to insert a value to an Object variable without using the setters. How can if be possible.
This is an example
Class X{
String variableName;
// getters and setters
}
Now i have a function which contains the variable name, the value to be set and an Object of the Class X.
I am trying to use a generic method to set the value to the Object(objectOfClass) with the value i have passed(valueToBeSet) in the corresponding variable(variableName).
Object functionName(String variableName, Object valueToBeSet, Object objectOfClass){
//I want to do the exact same thing as it does when setting the value using the below statement
//objectOfClass.setX(valueToBeSet);
return objectOfClass;
}
This code is not tested. You can try this.
Classes to import
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Method
public Object functionName(String variableName, Object valueToBeSet, Object objectOfClass) throws IntrospectionException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//I want to do the exact same thing as it does when setting the value using the below statement
//objectOfClass.setX(valueToBeSet);
Class clazz = objectOfClass.getClass();
BeanInfo beanInfo = Introspector.getBeanInfo(clazz, Object.class); // get bean info
PropertyDescriptor[] props = beanInfo.getPropertyDescriptors(); // gets all info about all properties of the class.
for (PropertyDescriptor descriptor : props) {
String property = descriptor.getDisplayName();
if(property.equals(variableName)) {
String setter = descriptor.getWriteMethod().getName();
Class parameterType = descriptor.getPropertyType();
Method setterMethod = clazz.getDeclaredMethod(setter, parameterType); //Using Method Reflection
setterMethod.invoke(objectOfClass, valueToBeSet);
}
}
return objectOfClass;
}
If you are sure that you really need this, please, think twice, but anyway:
import java.lang.reflect.Field;
...
X x = new X();
Field variableName = x.getClass().getDeclaredField("variableName");
// this is for private scope
variableName.setAccessible(true);
variableName.set(x, "some value");
There are two ways of setting values in object
1-Constructor Injection -- "Pushing" dependencies into a concrete class through constructor arguments.
2-Setter Injection -- "Pushing" dependencies into a concrete class through public properties. The "Setter" nomenclature is taken from Java where properties are getSomething() and setSomething(value).
As you don't want to use setters ,You can create a parameterised constructor to do so.Parameterized constructors are required to pass parameters on creation of objects.Except it I don't think that there is any other way of doing that without calling setters.

Categories

Resources