Issue caused by bytebuddy AgentBuilder$Transformer API changes - java

I am using bytebuddy to instrument method calls in tests. I am running into this issue:
Agent Error: java.lang.AbstractMethodError: Receiver class nz.ac.wgtn.nullannoinference.agent.NullLoggerAgent$4 does not define or inherit an implementation of the resolved method abstract transform(Lnet/bytebuddy/dynamic/DynamicType$Builder;Lnet/bytebuddy/description/type/TypeDescription;Ljava/lang/ClassLoader;Lnet/bytebuddy/utility/JavaModule;Ljava/security/ProtectionDomain;)Lnet/bytebuddy/dynamic/DynamicType$Builder; of interface net.bytebuddy.agent.builder.AgentBuilder$Transformer.
The critical issue is the last parameter of AgentBuilder$Transformer::transform of type ProtectionDomain. In version 1.10.20 this is abscent. I could upgrade but this does not solve my issue as I cannot control the version of bytebuddy being used as many of the programs I want to instrument already have a bytebuddy dependency through mockito, often a slightly older version.
Perhaps shading could work. Any advise how to proceed here ? I could always write multiple versions of the agent for different versions of bytebuddy but this seems very clumsy, and a maintenance nightmare.

I think I have figured it out -- actually it is rather easy, I am so used to lambdas that I did not see the obvious. This seems to work:
new AgentBuilder.Default()
..
.transform(
new AgentBuilder.Transformer() {
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule) {
return builder.visit(NullChecks.MethodWithoutReturnValues.VISITOR);
}
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule,ProtectionDomain pd) {
return builder.visit(NullChecks.MethodWithoutReturnValues.VISITOR);
}
}
)
I.e. just overload transform to support the two API versions.

Related

Specification of behavior when annotation missing from classpath is attached to a class

I am looking for a specification of what the behavior will be when a Java class is annotated with an annotation that is not present on the consumer's classpath. Specifically, when the annotated class is packaged as a jar and pulled in to another project (in Maven terms, an 'optional' or 'provided' dependency contains the annotation and the dependent elects not to depend on that).
I found an old Eclipse bug thread that mentions this: https://bugs.eclipse.org/bugs/show_bug.cgi?id=320965
My understanding is that annotations are supposed to be dropped from the class file if the annotation class isn't present.
I have observed the same behavior; that is, the class seems to load fine when the annotation is not found, but I cannot find this specified anywhere. I'm using OpenJDK.
(For those curious, the context is making a library dependency injection-friendly without tying it to a specific DI framework, so I'd like to use both CDI annotations and Guice annotations, for example, but consumers will probably not want to bring in both sets of annotations, if any at all)
Neither the Java Language Specification nor the Java Virtual Machine Specification covers this directly. The latter does not discuss annotations for verification or linking, so one could argue that missing annotation types should not cause a class loading failure. The JDK API documentation does not discuss this, except for missing classes in class-valued annotations. That looks like an omission.
The parser for user-defined (non-VM) annotations lives in sun.reflect.annotation.AnnotationParser. As you can see, unknown annotations are simply skipped:
try {
try {
sig = constPool.getUTF8At(typeIndex);
annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
} catch (IllegalArgumentException ex) {
// support obsolete early jsr175 format class files
annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex);
}
} catch (NoClassDefFoundError e) {
if (exceptionOnMissingAnnotationClass)
// note: at this point sig is "[unknown]" or VM-style
// name instead of a binary name
throw new TypeNotPresentException(sig, e);
skipAnnotation(buf, false);
return null;
}
There is also no way to detect that this happens. As a result, if you want to make sure that there are no unknown annotations present, you have to parse the class file with a different parser.

Instrument all implementations of a set of interfaces with ByteBuddy

Background: I want to instrument all implementations of a set of interfaces (within the same package) with a LogInterceptor (just logging that the method was called). Therefore I wrote a javaagent with byte-buddy. In general that is working fine, but I'm struggling with finding all implementations of a set of interfaces.
Assume we have a set of Java interfaces in a package my.company.api, then I tried it the following way:
public static void premain(String arguments, Instrumentation instrumentation) {
new AgentBuilder.Default()
.ignore(ElementMatchers.isInterface())
.ignore(ElementMatchers.isEnum())
.type(ElementMatchers.nameMatches("my\\.company\\.api\\..*"))
.transform(new AgentBuilder.Transformer() {
#Override
public DynamicType.Builder transform(DynamicType.Builder builder, TypeDescription typeDescription, ClassLoader classloader) {
return builder
.method(ElementMatchers.isPublic())
.intercept(MethodDelegation.to(LogInterceptor.class));
}
}).installOn(instrumentation);
}
I am quite new with byte-buddy, maybe someone can give me a hint what I am doing wrong.
First of all, you are not chaining the ignore matchers correctly; it should be:
.ignore(isInterface().or(isEnum()))
As for matching the interfaces, you can try the hasSuperType matcher. If you try to match interfaces of a given package, you might try:
hasSuperType(nameStartsWith("my.company.api.").and(isInterface()))
Using a prefix matcher is much more efficient compared to a regex.

Storing all classes that use an interface with reflection? [duplicate]

Can I do it with reflection or something like that?
I have been searching for a while and there seems to be different approaches, here is a summary:
reflections library is pretty popular if u don't mind adding the dependency. It would look like this:
Reflections reflections = new Reflections("firstdeveloper.examples.reflections");
Set<Class<? extends Pet>> classes = reflections.getSubTypesOf(Pet.class);
ServiceLoader (as per erickson answer) and it would look like this:
ServiceLoader<Pet> loader = ServiceLoader.load(Pet.class);
for (Pet implClass : loader) {
System.out.println(implClass.getClass().getSimpleName()); // prints Dog, Cat
}
Note that for this to work you need to define Petas a ServiceProviderInterface (SPI) and declare its implementations. you do that by creating a file in resources/META-INF/services with the name examples.reflections.Pet and declare all implementations of Pet in it
examples.reflections.Dog
examples.reflections.Cat
package-level annotation. here is an example:
Package[] packages = Package.getPackages();
for (Package p : packages) {
MyPackageAnnotation annotation = p.getAnnotation(MyPackageAnnotation.class);
if (annotation != null) {
Class<?>[] implementations = annotation.implementationsOfPet();
for (Class<?> impl : implementations) {
System.out.println(impl.getSimpleName());
}
}
}
and the annotation definition:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PACKAGE)
public #interface MyPackageAnnotation {
Class<?>[] implementationsOfPet() default {};
}
and you must declare the package-level annotation in a file named package-info.java inside that package. here are sample contents:
#MyPackageAnnotation(implementationsOfPet = {Dog.class, Cat.class})
package examples.reflections;
Note that only packages that are known to the ClassLoader at that time will be loaded by a call to Package.getPackages().
In addition, there are other approaches based on URLClassLoader that will always be limited to classes that have been already loaded, Unless you do a directory-based search.
What erickson said, but if you still want to do it then take a look at Reflections. From their page:
Using Reflections you can query your metadata for:
get all subtypes of some type
get all types annotated with some annotation
get all types annotated with some annotation, including annotation parameters matching
get all methods annotated with some
In general, it's expensive to do this. To use reflection, the class has to be loaded. If you want to load every class available on the classpath, that will take time and memory, and isn't recommended.
If you want to avoid this, you'd need to implement your own class file parser that operated more efficiently, instead of reflection. A byte code engineering library may help with this approach.
The Service Provider mechanism is the conventional means to enumerate implementations of a pluggable service, and has become more established with the introduction of Project Jigsaw (modules) in Java 9. Use the ServiceLoader in Java 6, or implement your own in earlier versions. I provided an example in another answer.
Spring has a pretty simple way to acheive this:
public interface ITask {
void doStuff();
}
#Component
public class MyTask implements ITask {
public void doStuff(){}
}
Then you can autowire a list of type ITask and Spring will populate it with all implementations:
#Service
public class TaskService {
#Autowired
private List<ITask> tasks;
}
The most robust mechanism for listing all classes that implement a given interface is currently ClassGraph, because it handles the widest possible array of classpath specification mechanisms, including the new JPMS module system. (I am the author.)
try (ScanResult scanResult = new ClassGraph().whitelistPackages("x.y.z")
.enableClassInfo().scan()) {
for (ClassInfo ci : scanResult.getClassesImplementing("x.y.z.SomeInterface")) {
foundImplementingClass(ci); // Do something with the ClassInfo object
}
}
With ClassGraph it's pretty simple:
Groovy code to find implementations of my.package.MyInterface:
#Grab('io.github.classgraph:classgraph:4.6.18')
import io.github.classgraph.*
new ClassGraph().enableClassInfo().scan().withCloseable { scanResult ->
scanResult.getClassesImplementing('my.package.MyInterface').findAll{!it.abstract}*.name
}
What erikson said is best. Here's a related question and answer thread - http://www.velocityreviews.com/forums/t137693-find-all-implementing-classes-in-classpath.html
The Apache BCEL library allows you to read classes without loading them. I believe it will be faster because you should be able to skip the verification step. The other problem with loading all classes using the classloader is that you will suffer a huge memory impact as well as inadvertently run any static code blocks which you probably do not want to do.
The Apache BCEL library link - http://jakarta.apache.org/bcel/
Yes, the first step is to identify "all" the classes that you cared about. If you already have this information, you can enumerate through each of them and use instanceof to validate the relationship. A related article is here: https://web.archive.org/web/20100226233915/www.javaworld.com/javaworld/javatips/jw-javatip113.html
Also, if you are writing an IDE plugin (where what you are trying to do is relatively common), then the IDE typically offers you more efficient ways to access the class hierarchy of the current state of the user code.
I ran into the same issue. My solution was to use reflection to examine all of the methods in an ObjectFactory class, eliminating those that were not createXXX() methods returning an instance of one of my bound POJOs. Each class so discovered is added to a Class[] array, which was then passed to the JAXBContext instantiation call. This performs well, needing only to load the ObjectFactory class, which was about to be needed anyway. I only need to maintain the ObjectFactory class, a task either performed by hand (in my case, because I started with POJOs and used schemagen), or can be generated as needed by xjc. Either way, it is performant, simple, and effective.
A new version of #kaybee99's answer, but now returning what the user asks: the implementations...
Spring has a pretty simple way to acheive this:
public interface ITask {
void doStuff();
default ITask getImplementation() {
return this;
}
}
#Component
public class MyTask implements ITask {
public void doStuff(){}
}
Then you can autowire a list of type ITask and Spring will populate it with all implementations:
#Service
public class TaskService {
#Autowired(required = false)
private List<ITask> tasks;
if ( tasks != null)
for (ITask<?> taskImpl: tasks) {
taskImpl.doStuff();
}
}

Can I use some kind of assisted Inject with Dagger?

With Google Guice or Gin I can specify parameter with are not controlled by the dependency injection framework:
class SomeEditor {
#Inject
public SomeEditor(SomeClassA a, #Assisted("stage") SomeClassB b) {
}
}
The assisted parameter stage is specified at the time an instance of SomeEditor is created.
The instance of SomeClassA is taken from the object graph and the instance of SomeClassB is taken from the caller at runtime.
Is there a similar way of doing this in Dagger?
UPDATE: As of Dagger 2.31 from January 2021, Dagger now natively supports assisted injection, which is recommended over the Square and Auto options. (Those other options still work, but may require extra setup compared to the native option.)
class SomeEditor {
#AssistedInject public SomeEditor(
SomeClassA a, #Assisted SomeClassB b) {
// ...
}
}
#AssistedFactory interface SomeEditorFactory {
SomeEditor create(SomeClassB b);
}
(original answer)
Because factories are a separate type of boilerplate to optimize away (see mailing list discussion here), Dagger leaves it to a sister project, AutoFactory. This provides the "assisted injection" functionality Guice offers via FactoryModuleBuilder, but with some extra benefits:
You can keep using AutoFactory with Guice or Dagger or any other JSR-330 dependency injection framework, so you can keep using AutoFactory even if you switch between them.
Because AutoFactory generates code, you don't need to write an interface to represent the constructor: AutoFactory will write a brand new type for you to compile against. (You can also specify an interface to implement, if you'd prefer, or if you're migrating from Guice.)
Because all the type inspection happens at compile-time, it produces plain old Java, which doesn't have any slowness due to reflection and which works well with debuggers and optimizers. This makes the Auto library particularly useful for Android development.
Example, pulled from AutoFactory's README, which will produce a SomeClassFactory with providedDepA in an #Inject-annotated constructor and depB in a create method:
#AutoFactory
final class SomeClass {
private final String providedDepA;
private final String depB;
SomeClass(#Provided #AQualifier String providedDepA, String depB) {
this.providedDepA = providedDepA;
this.depB = depB;
}
// …
}
Just like #xsveda, I also wrote an answer about this in this other question, which I'll also reproduce here.
Today, for assisted injection with Dagger you probably want to use AssistedInject. I wrote about it in this blogpost, but I'll add a full example here to make things easier.
First thing you need are the dependencies:
compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'
Then here's how it can look like:
class ImageDownloader #AssistedInject constructor(
private val httpClient: HttpClient,
private val executorService: ExecutorService,
#Assisted private val imageUrl: URL,
#Assisted private val callback: ImageCallback
) {
#AssistedInject.Factory
interface Factory {
fun create(imageUrl: URL, callback: ImageCallback): ImageDownloader
}
}
First thing is that instead of annotating the constructor with #Inject, we annotate it with #AssistedInject. Then we annotate the parameters that will have to go through the factory, which is the opposite of what AutoFactory expects. Finally, we need an inner factory interface annotated with #AssistedInject.Factory that has a single method that receives the assisted parameters and returns the instance we're interested in.
Unfortunately, we still have an extra step here:
#AssistedModule
#Module(includes = [AssistedInject_AssistedInjectModule::class])
interface AssistedInjectModule
We don't necessarily need a dedicated module for it, even though that's a valid option. But we can also have those annotations in another module that is already installed in the component. The nice thing here is that we only need to do it once, and after that any factory will automatically become part of the graph.
With that, you can basically inject the factory and ask for your object as you'd normally do.
Yes, please check this Square project: square/AssistedInject
Currently it is not in 1.0 yet for purpose. They wait until Dagger will introduce a public API for registering those generated Module classes automatically - see this issue. With that you won't have to reference them in your Dagger code as in this example from README:
#AssistedModule
#Module(includes = AssistedInject_PresenterModule.class)
abstract class PresenterModule {}

Security: Restrict internal access by third-party software

I have a Java application in which third-party "plugins" can be loaded by users to enhance the user experience. An API exists for use by these plugins, but the third-party software should be restricted from access to internal application classes for purpose of security. The restricted package to plugins would be "com.example" and the allowed would be "com.example.api". The API classes do make calls to the internal, obfuscated classes.
After researching this, I came across a couple methods of SecurityManager: checkMemberAccess(Class, int) and checkPackageAccess(String), which both seemed to be viable paths to my goal. However, after doing some tests and further research, I have found that checkMemberAccess only applies to reflection calls, and checkPackageAccess is only called when a class loader invokes loadClass.
What is a reasonable way to restrict access to a package (com.example, but not com.example.api)?
I suggest writing a custom class loader for the plugins, which hides the existence of the com.example package from classes loaded using that classloader. Usually class loaders delegate to their parent, but there are several implementations out in the wild which will do so only in part or not at all. I believe e.g. ant uses this technique. When loaded with such a class loader, any class linked against forbidden functinality would fail to load. Or if the implementation used lazy linking, and it did load successfully, it would still fail during execution of the forbidden code.
Having denied your plugins link-time access to the forbidden package, you can then use a SecurityManager to deny runtime access via reflection, and also to deny creation of a new class loader which might be used to circumvent yours.
class RestrictingClassLoader extends URLClassLoader {
#Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (!name.startsWith("com.example.") || name.startsWith("com.example.api."))
return super.loadClass(name);
return findClass(name);
}
}
class RestrictingSecurityManager extends SecurityManager {
private boolean isRestricted() {
for (Class<?> cls: getClassContext())
if (cls.getClassLoader() instanceof RestrictingClassLoader)
return true;
return false;
}
// Implement other checks based on isRestricted().
}

Categories

Resources