Bytebuddy get value of proteced field - java

Im struggling to figure out how to access a protected field using ByteBuddy and what approach to take.
Background: Id like to intercept a class from a dependency I have on my class path. Im creating a junit test report and need to intercept org.assertj.core.api.AbstractAssert in order to capture the actual field value from that class.
Iv tried...
Class<?> type = new ByteBuddy()
.redefine(AbstractAssert.class)
.visit(Advice.to(MyAdvices.class).on(ElementMatchers.isMethod()))
.make().load(AbstractAssert.class.getClassLoader()).getLoaded();
log.info(type.getFields().toString());
Class already loaded: class org.assertj.core.api.AbstractAssert
Im not even sure if this is the correct approach for what Im trying to achieve
Any help appreciated

You cannot just change a class on the JVM. Either you would need to use a different class loader and load the class regularly, or a Java agent. For an agent, Byte Buddy supplies a RedefinitionStrategy which you can use to integrate this in your above example. Also have a look at the byte-buddy-agent project.

Related

How to know dynamically if the loaded class is application class?

I am in a situation that I want to do some rewriting on loaded,i.e., currently running application class. I do not want to rewrite loaded library class. Thus I need to sort of filter the rewriting based either on the type of the class, being application or none application class, or another way I could do it is by checking the ClassLoader and see if it is of Application Class type.
To give some context let's assume I have the following code
URLClassLoader urlcl = new URLClassLoader(cp);
Class c = urlcl.loadClass(_className);
Assuming that _className is the current running class, that was intercepted by a listener, how can I know if this class c is an application class or not?
Much appreciated!
I'm not entirely sure of what do you mean by application class, but those hints still might be helpful.
You can simply check if one class is subtype of another with:
public static boolean is1stSubTypeOf2nd(Class clazz1, Class clazz2) {
return clazz2.isAssignableFrom(clazz1);
}
If you would like to check if the class belongs to some package (to check if it is the class from standard API, third party library or not), you can use:
public static boolean isInPackage(Class clazz, String packageName) {
return clazz.getPackageName().contains(packageName);
}
Further the standard API is able to provide you an info about all super classes of given class.

Injecting spring service in external groovy class created at runtime

I have an Spring-powered app and want to integrate groovy. Specifically, I have one abstract java class with a set of abstract method definitions and one repository inyected with autowired.
This class must be implemented by several final groovy external classes (one for each client).
At this moment, I am calling the Groovy class in java this way:
final Class parsedClass = groovyClassLoader.parseClass(groovyFile);
final GroovyObject groovyObject = (GroovyObject) parsedClass.newInstance();
final Object response = groovyObject.invokeMethod(methodName, methodParameters);
The problem is that I need to autowired the repository variable in each Groovy external class but currently are null.
How can I notify the Groovy class to get the inyected repository variable when I create it at runtime?
Thanks!
Edit
Y have solved it using the setProperty method from groovyObjectObject this way:
groovyObject.setProperty("myRepository", myRepositoryImpl);
The instance here is not created by spring, hence I don't think spring can automagically set the instance of repository in the groovyObject that you have.
However, if you can can autowire the repository into the class thats generating the groovyObject then you can manually inject the repo in the newInstance call.
parsedClass.newInstance(repository:your_autowired_repo_ref)
I have solved it using the setProperty method from groovyObjectObject this way:
groovyObject.setProperty("myRepository", myRepositoryImpl);

Use Constants interface in GWT Project

I have not yet used Constants interface in GWT and I am having problem to run the example CellTable. The deferred binding fails and the central error message is: "No resource found for contactDataBaseCategories". contactDataBaseCategories is a method defined in the interface DataBaseConstants and returns an array of Strings. I suspect I must create a properties (txt?) file and to define the categories, but I am not sure, since I come across this case for the first time. How can I do it properly to make the example of the CellTable run?
Update: I have created the ContactDatabase.DatabaseConstants.properties file in the same package in which the interface is declared, I have added the line in the file:
contactDataBaseCategories = friends, coWorkers, other
but it still does not work. The error is again : "No resource found for contactDataBaseCategories" and then
"Deferred Binding failed for com.al.celltablöeexample.ContactDatabase.DatabaseConstants".
What going wrong?
This is how i do it
Constant interface
public interface DataBaseConstants extends Constants
{
#Key("contact-database-categories")
String contactDataBaseCategories();
}
property file. DataBaseConstants.properties
contact-database-categories = "Your String"
You can use it
public DataBaseConstants dbConstant= GWT.create( DataBaseConstants .class );
dbConstant.contactDataBaseCategories();
Edited
If you want to pass string array then you can do it like this
#DefaultStringArrayValue({"cat1", "cat2", "cat3", "cat4", "cat5"})
String[] contactDataBaseCategories();
More about Constants
I have finally managed it. The problem was that it could not find the resource/file: ContactDatabase.DatabaseConstants.properties. I have changed it to DatabaseConstants.properties and I removed the inner interface to its own file. The same I did in the class CwCellTable on the interface CwConstants. In the example page moreover, the instantiation of the CwConstants interface is missed, and one must do also this (in the constructor), like in the ContactDatabase class.
Just to add to Dilantha's answer you can then set
contact-database-categories = Family, Friends, Coworkers, Businesses, Contacts
in order to comply with the example.
Tip : In order to make the example work create a costructor in CwCellList and add the following :
initWidget(onInitialize());

Automatic factory registration

i'm just learning java, and i meet some problems.
Here we have simple factory pattern:
public class SomeFactory {
...
public static void registerProduct(String name, Class<? extends IProduct > f)
}
public SomeProduct implements IProduct {
static {
SomeFactory.register("some product", SomeProduct.class);
}
...
}
All products should register themselves at factory.
But before using this code, all Products classes should be loaded.
I can put Class.forName() somewhere, for example in main function.
But i want to avoid such sort of manual classes loading. I want just add new IProduct
implementations, without updating other parts(such as SomeFactory or Main methods, etc.).
But i wonder, is it possible to automatically load some classes(marked with annotation, for example)?
P.S I want to notice, that no other classes will be added at run-time, all IProduct implementations are known before compiling.
UPD#1
Thank for your answering!
But is it possible to make auto-generated property-file with IProduct instances?
I mean is it possible to make some build-time script(for maven for example) that generates property-file or loader code? Are there such solutions or frameworks?
UPD#2
I finished with using Reflections library that provides run-time information, by scanning classpath at startup.
This is possible, but not easily. It would need to scan all the classes in the classpath to see if they have an annotation or implement the IProduct interface. See How do you find all subclasses of a given class in Java? for answers to such a problem.
I would do keep it simple and just have a list of classes to load, either in the factory itself, or in an external file (properties file, for example).
Have each product register itself, using a static block like this:
class MyProduct1{
static{
SomeFactory.register(MyProduct1.getClass());
}
..
..
}
An external property file can keep track of all Products.
Your main method can parse this list of Products and do a Class.forName("..").
This way you wouldnt need to code any specific product, just the property file keeps changing. Ah! yes adding security registration would also be a plus point.
Note: I'm just proposing an idea, I'vent tried it myself :)

ClassCast Exception is thrown after I've used ASM Toolkit to replace the body of a static method

I've been trying to use the ASM bytecode toolkit to replace the body of a public and static method in a class. The actual body replacement seems to work fine and I do get the expected behavior if execute the following once the transformation has completed:
Class cls = loadClass("ext.hm.cmd.MyProg");
cls.getMethod("hello").invoke(instance);
However if I try to cast the new instance to MyProg like so
MyProg p = (MyProg) instance;
p.hello();
I get the error message:
java.lang.ClassCastException: ext.hm.cmd.MyProg cannot be cast to ext.hm.cmd.MyProg
As I'm not adding or deleting any methods in the class I can't really understand why I get this error. Has anyone seen this before and if so, what is the cause of it and how can I solve it?
Thanks
Daniel Martinsson
Kind of a guess, but I'd say you have the same named class loaded by two different ClassLoaders. Those are actually considered two separate classes and one cannot be cast to the other.
One is loaded before the line
MyProg p = (MyProg) instance;
is executed. The other is loaded through your call to loadClass.
To fix this you would probably need the class that performs the line of code above to be loaded by the same ClassLoader that loads the altered instance of MyProg. Then it should work.
If you use spring boot dev tool, you can try exclude it from the project

Categories

Resources