I hava A Class in another jar and i use it in B bean.
Now i want to add log for method in A Class. How can i do this in my project without fix the jar.
My mind:
use ApplicationListener to redefine class before bean init.
do something in onApplicationEvent() to redefine the A class. // this is my question.
I know that can use asm or other tool to fix bytecode. I hava see instrument and do not find solution . https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/Instrumentation.html
How to obtain instance of Instrumentation in Java
A class.
public class A {
public void find(){
System.out.println("aaa");
//i want to add log here.
}
B bean
#Service public class B {
public A get(){
return new A();
}
ApplicationListener
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if(event.getApplicationContext().getParent() != null){
return;
}
// redefine class
}
then when i use b.get().find() it will print the log i add.
find my solution.
using javassist modify the class. and load it (using CtClass.toClass())in advance.
https://www.javassist.org/tutorial/tutorial.html
Related
I have the following classes :
Class 1:
package com.assets;
#Component
#Scope("request)
public class AssetDetailsImpl implements AssetApi
{
public void function1(){
....
}
public void function2(){
AssetUtil.test1();
}
}
Class 2:
package com.assets;
#Component
public class AssetUtil
{
#Autowired
AssetDetailsImpl impl;
//some functions
public static void test1{
impl.function1();// NPE I am getting
}
Here my auto wiring not working, its coming null. Both the classes are in the same package. Is it because of the request scope which is there in AssetDetailsImpl? I even tried with #Inject that also was not working. Can anyone please help me to resolve this? Thanks in advance!
I have tried removing the scope, but then also the same problem.
I have also tried:
AssetUtil(AssetDetailsImpl impl) {
this.impl = impl;
}
But I am not sure how to deal with the static thing then also how to invoke this constructor?
The method test1 is static.
But Spring doesn't work with static members because it creates instances of the beans.
Remove static:
public void test1{
impl.function1();
}
And now you have to make sure that the client of this method is also using autowiring to get an instance of AssetUtil
It looks to me like the issue is that the AssetDetailsImpl Component is Request-scoped, which means it comes and goes with each HTTP request, while the AssetUtil Component which is trying to use it is default-scoped, which is Application/singleton scope.
Personally, I try to use singletons as much as possible. I wouldn't use request scope for the first Component.
i am kind of stuck on a problem with creating beans, or probably i got the wrong intention.. Maybe you can help me solve it:
I got a application which takes in requests for batch processing. For every batch i need to create an own context depending on the parameters issued by the request.
I will try to simplyfy it with the following example:
I receive a request to process in a batch FunctionA which is a implementation for my Function_I interface and has sub-implementation FunctionA_DE and FunctionA_AT
Something like this:
public interface Function_I {
String doFunctionStuff()
}
public abstract class FunctionA implements Function_I {
FunctionConfig funcConfig;
public FunctionA(FunctionConfig funcConfig) {
this.funcConfig = funcConfig;
}
public String doFunctionStuff() {
// some code
String result = callSpecificFunctionStuff();
// more code
return result;
}
protected abstract String callSpecificFunctionStuff();
}
public class FunctionA_DE extends FunctionA {
public FunctionA_DE(FunctionConfig funcConf) {
super(funcConf)
}
protected String callSpecifiFunctionStuff() {
//do some specificStuff
return result;
}
}
public class FunctionA_AT extends FunctionA {
public FunctionA_AT(FunctionConfig funcConf) {
super(funcConf)
}
protected String callSpecifiFunctionStuff() {
//do some specificStuff
return result;
}
}
what would be the Spring-Boot-Way of creating a instance for FunctionA_DE to get it as Function_I for the calling part of the application, and what should it look like when i add FunctionB with FunctionB_DE / FunctionB_AT to my classes..
I thought it could be something like:
PSEUDO CODE
#Configuration
public class FunctionFactory {
#Bean(SCOPE=SCOPE_PROTOTYPE) // i need a new instance everytime i call it
public Function_I createFunctionA(FunctionConfiguration funcConfig) {
// create Function depending on the funcConfig so either FunctionA_DE or FunctionA_AT
}
}
and i would call it by Autowiring the FunctionFactory into my calling class and use it with
someSpringFactory.createFunction(functionConfiguration);
but i cant figure it out to create a Prototype-Bean for the function with passing a parameter.. And i cant really find a solution to my question by browsing through SO, but maybe i just got the wrong search terms.. Or my approach to solve this issue i totally wrong (maybe stupid), nobody would solve it the spring-boot-way but stick to Factories.
Appreciate your help!
You could use Springs's application context. Create a bean for each of the interfaces but annotate it with a specific profile e.g. "Function-A-AT". Now when you have to invoke it, you can simply set the application context of spring accordingly and the right bean should be used by Spring.
Hello everyone and thanks for reading my question.
after a discussion with a friend who is well versed in the spring framework i came to the conclusion that my approach or my favoured solution was not what i was searching for and is not how spring should be used. Because the Function_I-Instance depends on the for the specific batch loaded configuration it is not recommended to manage all these instances as #Beans.
In the end i decided to not manage the instances for my Function_I with spring. but instead i build a Controller / Factory which is a #Controller-Class and let this class build the instance i need with the passed parameters for decision making on runtime.
This is how it looks (Pseudo-Code)
#Controller
public class FunctionController {
SomeSpringManagedClass ssmc;
public FunctionController(#Autowired SomeSpringManagedClass ssmc) {
this.ssmc = ssmc;
}
public Function_I createFunction(FunctionConfiguration funcConf) {
boolean funcA, cntryDE;
// code to decide the function
if(funcA && cntryDE) {
return new FunctionA_DE(funcConf);
} else if(funB && cntryDE) {
return new FunctionB_DE(funcConf);
} // maybe more else if...
}
}
I'm quite new to spring (switching from PHP to Java).
In my code I have a java.lang.reflect.Method objects and I need to instantiate it's class with all it's dependencies.
Normally I'd use #Autowired annotation in my code, but it's not possible because my code gets different Method objects, not specific classes.
Question is - how to get a class instance from dependency container without using annotations and having just class name?
In php i used libraries which gave me access to container and I could just get DI services by it's class name just like:
$this->container->get('My\Class\Name');
In spring I tried:
#Autowired
private ApplicationContext context;
void myMethod(Method method){
this.context.getBean(method.getClass());
and
this.context.getBean(method.getClass().getName());
and that was resulting in NullPointerException.
EDIT
Thanks for quick replys,
I tried using
context.getBean(method.getDeclaringClass());
and
context.getBean(method.getDeclaringClass().getSimpleName());
And it both resulted in NullPointerException as well.
Actually it's okay for my needs to get that class by class or by name. I'm trying to write my own command bus for CQRS.
Let me show you some code:
Handler:
public class SimpleCommandBus implements CommandBus {
#Autowired
private ApplicationContext context;
private Map<Class, Method> registry = new HashMap<>();
#Override
public void register(Class c, Method o) {
registry.put(c, o);
}
#Override
public void dispatch(Object command) {
if (!registry.containsKey(command.getClass())) {
throw new CommandDispatchException(String.format("Handler for command %s was not defined.", command));
}
Method method = registry.get(command.getClass());
Object handler = context.getBean(method.getDeclaringClass().getSimpleName());//line causing exception
Service class:
#Service
public class TestHandler {
public void handle(TestCommand command){
System.err.println(command.getId());
}
}
Calling command bus:
Method method = TestHandler.class.getMethod("handle", TestCommand.class);
TestCommand command = new TestCommand("Test command");
commandBus.register(TestCommand.class, method);
commandBus.dispatch(command);
Use java.lang.reflect.Method.getDeclaringClass() to find in which class the given method is declared. method.getClass() will return the type of method object which is java.lang.reflect.Method.
#Autowired
AplicationContext ctx;
...
Object bean = ctx.getBean(method.getDeclaringClass());
In Spring the default name is the simple name.
Plus as in Karols answer you must use getDeclaringClass() to get the class of the class with the method.
So you must call
this.context.getBean(method.getDeclaringClass().getSimpleName());
Imagine there is class
public class sample {
private String fieldName;
}
Which already compiled and the part of the claspath when the jam statsup.
I want add #notnull and #size(min=1,max=5) dynamically for fieldName(not class level)
Any suggestions plz
I'll try to answer the question as a ByteBuddy question, without the synopsis of validation.
Using ByteBuddy, you can change your classes at runtime. But in certain conditions, like you are not on Android (Dalvik's virtual machine is different than ordinary JVMs), and you shouldn't change an already loaded class.
class Subclass {
public void func() {
}
}
class FunctionalInterfaceImpl implements FunctionalInterface {
#Override
public Class<? extends Annotation> annotationType() {
return FunctionalInterface.class;
}
}
public class TryingByteBuddy {
public static void main(String[] args) {
new ByteBuddy()
.redefine(TypePool.Default.ofClassPath().describe("com.experiments.Subclass").resolve(),
ClassFileLocator.ForClassLoader.ofClassPath())
.annotateType(new FunctionalInterfaceImpl())
.make()
.load(ClassLoader.getSystemClassLoader());
System.out.println(Arrays.deepToString(new Subclass().getClass().getAnnotations()));
}
}
In this code Subclass is a class that doesn't have the #FunctionalInterface annotation. Now when you run you will find it has it.
NOTES ON THIS CODE:
You will find that we didn't use Subclass.class when trying to redefine the class
This is to prevent loading of the class before creating the alternative
Using Subclass.class will invoke the class loader to load the original class, this prevents ByteBuddy from doing its work
We "implemented" the annotation interface we want to add (FunctionalInterface in this example).
For more info:
ByteBuddy tutorial
Do we always require a beans.xml for a dependency injection in a simple java program using only CDI,and do we need to construct a bean to get the objects injected???
Below are the codes for simple java project with dependency Injection::
Interface
public interface Hello
{
public void sayHello(String str);
}
class
public class HelloImpl1 implements Hello{
public void sayHello(String str){
System.out.println("Hello from 1st block")
}
}
class
public class HelloImpl2 implements hello{
public void sayHello(String str){
System.out.println("Hello from 2nd block")
}
}
Class
public CallingHello(){
#Inject
Hello hello;
public void callHello(){
hello.sayHello("Hey");
}
}
Class
public Test(){
public static void main(String[] args){
CallingHello hello=new CallingHello();
hello.callHello();
}
Thats all i am doing and while running the test class its throwing nullpointerexception,and i am making simple classes no bean in eclipse,m i going right??
You can use autowiring , in order to inject dependencies (and possibly apply post processors) to an object that is not part of the application context.
You can use java config class with factory methods to configure ApplicationContext:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class AppConfig {
#Bean(name="HelloImpl1")
public HelloImpl1 helloImpl1() {
return new HelloImpl1();
}
#Bean(name="HelloImpl2")
public HelloImpl1 helloImpl2() {
return new HelloImpl2();
}
}
And then to instantiate:
ApplicationContext ctx =
new AnnotationConfigApplicationContext(AppConfig.class);
HelloImpl1 helloImpl1= (HelloImpl1)ctx.getBean("HelloImpl1");
helloImpl1.sayHello("#?*")
If you are using Spring for the dependency injection, you always need a configuration file. But it does not need to be named beans.xml.
Yes the beans are injected in other beans.
Technically no you don't have use an XML file define your beans and inject dependencies. It depends on the type of ApplicationContext you use. But, for most practical applications you'll use one of the AbstractXMLContextApplication instances which will load an XML file to figure out the beans your app has declared. The name of that file doesn't have to be beans.xml. That's a convention used, but it you don't have to name it that. You can override which file it looks for when you constructor the implementation of AbstractXMLApplicationContext object.
All you need to do is construct the bean container, and it will load the beans, resolve the dependencies, and startup the program (if you are using init-method). Typically my Spring Container Java programs look like this:
ApplicationContext context = null;
try {
context = new FileSystemXmlApplicationContext( new String[] { file } );
// pause until we want to shutdown or after something happens.
System.in.readLine();
} finally {
context.close(); // remember to clean up!
}
And I let the init methods on the bean startup my application.