Added annotation processing from "dev"-Branche
This commit is contained in:
10
pom.xml
10
pom.xml
@@ -127,6 +127,16 @@
|
|||||||
<version>6.1.0</version>
|
<version>6.1.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.bytebuddy</groupId>
|
||||||
|
<artifactId>byte-buddy</artifactId>
|
||||||
|
<version>LATEST</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.bytebuddy</groupId>
|
||||||
|
<artifactId>byte-buddy-agent</artifactId>
|
||||||
|
<version>LATEST</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@@ -2,9 +2,13 @@ package org.openautonomousconnection.protocol.annotations;
|
|||||||
|
|
||||||
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Annotation to provide metadata about protocol handlers or classes.
|
* Annotation to provide metadata about protocol handlers or classes.
|
||||||
*/
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface ProtocolInfo {
|
public @interface ProtocolInfo {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -0,0 +1,83 @@
|
|||||||
|
package org.openautonomousconnection.protocol.annotations.processing;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.reflections.GenericReflectClass;
|
||||||
|
import net.bytebuddy.agent.ByteBuddyAgent;
|
||||||
|
import net.bytebuddy.agent.builder.AgentBuilder;
|
||||||
|
import net.bytebuddy.asm.Advice;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.instrument.Instrumentation;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.any;
|
||||||
|
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
|
||||||
|
|
||||||
|
public class CallTracker<A extends Annotation> extends GenericReflectClass<A> {
|
||||||
|
private static final AtomicReference<Class<? extends Annotation>> atomicClass = new AtomicReference<>();
|
||||||
|
|
||||||
|
public CallTracker(CallInterceptor interceptor) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
atomicClass.set(this.persistentClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void premain(String agentArgs, Instrumentation inst) {
|
||||||
|
ByteBuddyAgent.install();
|
||||||
|
|
||||||
|
new AgentBuilder.Default()
|
||||||
|
.type(any()) // instrument all classes, you can restrict here
|
||||||
|
.transform((builder, type, classLoader, module, protectionDomain) ->
|
||||||
|
builder.visit(Advice.to(CallInterceptor.class).on(isMethod()))
|
||||||
|
).installOn(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class CallInterceptor {
|
||||||
|
private static Set<CallInterceptor> interceptors = new HashSet<>();
|
||||||
|
|
||||||
|
public CallInterceptor() {
|
||||||
|
interceptors.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code executed on any method call
|
||||||
|
*/
|
||||||
|
public abstract void onCall(Method method, @Nullable StackTraceElement callerMethod);
|
||||||
|
|
||||||
|
@Advice.OnMethodEnter
|
||||||
|
static void intercept(@Advice.Origin Method method) {
|
||||||
|
|
||||||
|
for(CallInterceptor interceptor : interceptors) {
|
||||||
|
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
|
||||||
|
|
||||||
|
if (stack.length <= 3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
StackTraceElement caller = stack[3];
|
||||||
|
|
||||||
|
interceptor.onCall(method, caller);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (method.isAnnotationPresent(atomicClass.get())) {
|
||||||
|
// StackTraceElement[] stack = Thread.currentThread().getStackTrace();
|
||||||
|
// // stack[0] = getStackTrace
|
||||||
|
// // stack[1] = intercept
|
||||||
|
// // stack[2] = Advice dispatcher
|
||||||
|
// // stack[3+] = your actual caller
|
||||||
|
// if (stack.length <= 3)
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// StackTraceElement caller = stack[3];
|
||||||
|
//
|
||||||
|
// System.out.println("Annotated method " + method.getName()
|
||||||
|
// + " was called by " + caller.getClassName() + "." + caller.getMethodName());
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,99 @@
|
|||||||
|
// Author: maple
|
||||||
|
// date: 9/29/25
|
||||||
|
|
||||||
|
package org.openautonomousconnection.protocol.annotations.processing;
|
||||||
|
|
||||||
|
import dev.unlegitdqrk.unlegitlibrary.reflections.annotation.processing.AnnotationProcessor;
|
||||||
|
import org.openautonomousconnection.protocol.annotations.ProtocolInfo;
|
||||||
|
import org.openautonomousconnection.protocol.exceptions.IncompatibleProtocolSideException;
|
||||||
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process ProtocolInfo annotation and throw exception on mismatching annotation and ProtocolSide
|
||||||
|
*/
|
||||||
|
public class ProtocolInfoProcessing extends AnnotationProcessor<ProtocolInfo> {
|
||||||
|
|
||||||
|
private final CallTracker<ProtocolInfo> tracker;
|
||||||
|
|
||||||
|
private final AtomicReference<Set<Method>> methodReferences = new AtomicReference<>();
|
||||||
|
private final AtomicReference<Set<Class<?>>> typeReferences = new AtomicReference<>();
|
||||||
|
|
||||||
|
public ProtocolInfoProcessing() {
|
||||||
|
super("org.openautonomousconnection.protocol");
|
||||||
|
|
||||||
|
this.process();
|
||||||
|
|
||||||
|
this.methodReferences.set(this.annotatedMethods);
|
||||||
|
|
||||||
|
this.typeReferences.set(this.annotatedTypes);
|
||||||
|
|
||||||
|
this.tracker = new CallTracker<>(new CallTracker.CallInterceptor() {
|
||||||
|
@Override
|
||||||
|
public void onCall(Method method, @Nullable StackTraceElement callerMethod) {
|
||||||
|
ProtocolVersion.ProtocolSide side, callerSide;
|
||||||
|
|
||||||
|
Object o;
|
||||||
|
|
||||||
|
if((o = methodGetByName(callerMethod.getMethodName())) != null)
|
||||||
|
callerSide = ((Method) o).getAnnotation(ProtocolInfo.class).protocolSide();
|
||||||
|
else if((o = typeHasAnnotation(callerMethod.getClassName())) != null)
|
||||||
|
callerSide = ((Class<?>) o).getAnnotation(ProtocolInfo.class).protocolSide();
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
if(methodReferences.get().contains(method))
|
||||||
|
side = method.getAnnotation(ProtocolInfo.class).protocolSide();
|
||||||
|
|
||||||
|
else if(typeReferences.get().contains(method.getDeclaringClass()))
|
||||||
|
side = method.getDeclaringClass().getAnnotation(ProtocolInfo.class).protocolSide();
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(callerSide.equals(ProtocolVersion.ProtocolSide.CLIENT) &&
|
||||||
|
!side.equals(callerSide))
|
||||||
|
throw new IncompatibleProtocolSideException(callerSide, side);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method methodGetByName(String methodName) {
|
||||||
|
for(Method method : this.annotatedMethods)
|
||||||
|
if(method.getName().equals(methodName))
|
||||||
|
return method;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> typeHasAnnotation(String typeName) {
|
||||||
|
for(Class<?> type : this.annotatedTypes)
|
||||||
|
if(type.getName().equals(typeName))
|
||||||
|
return type;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processType(Class<?> type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processMethod(Method method) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processField(Field field) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processConstructor(Constructor constructor) {
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,12 @@
|
|||||||
|
package org.openautonomousconnection.protocol.exceptions;
|
||||||
|
|
||||||
|
import org.openautonomousconnection.protocol.versions.ProtocolVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when an unsupported protocol side method is called.
|
||||||
|
*/
|
||||||
|
public class IncompatibleProtocolSideException extends RuntimeException {
|
||||||
|
public IncompatibleProtocolSideException(ProtocolVersion.ProtocolSide callerSide, ProtocolVersion.ProtocolSide side) {
|
||||||
|
super(callerSide.name() + " is incompatible with called method of ProtocolSide " + side.name());
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user