Вы можете использовать аспектj, чтобы достичь того, что вы хотите. Допустим, у нас есть скомпилированный jar с методом, аналогичным тому, который вы описали: вы хотите перехватывать вызовы метода logStuff
из определенного местоположения (-ей) в вашем приложении и изменять logi c для переноса аргумента в DummyContainer
объект. Вот как может выглядеть ваш код.
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public static @interface DummyAnnotation {
Class type();
}
//that is your target method
public static void logStuff(@DummyAnnotation(type = String.class) Object data) {
if(data instanceof String) {
System.out.println("String: " + data);
} else {
System.out.println("Not a string " + data);
}
}
Класс фиктивного контейнера:
public static class DummyContainer {
private String string;
private Class clazz;
public DummyContainer(String string, Class clazz) {
this.clazz = clazz;
this.string = string;
}
@Override
public String toString() {
return "DummyContainer=[clazz: " + clazz + ", string: " + string + "]";
}
}
Аспект:
@Aspect
public class WrapperAspect {
@Pointcut("call(* "
/**method to intercept*/
+ "com.yourpackage.YourType.logStuff(Object)) && args(param) && "
/**only calls made from within that location
* will be intercepted. Remove it to intercept
* calls from everywhere*/
+ "within(test.Runner)")
public void logStuffPointcut(Object param) {}
@Around("logStuffPointcut(param)")
public void simpleWrap(Object param, ProceedingJoinPoint jp) throws Throwable {
String calledMethodName = jp.getSignature().getName();
Class type = jp.getSignature().getDeclaringType();
Method method = type.getDeclaredMethod(calledMethodName, Object.class);
DummyAnnotation annotation = method.getParameters()[0].getAnnotation(DummyAnnotation.class);
DummyContainer wrapped = new DummyContainer((String) param, (Class)annotation.type());
//code before method call
jp.proceed(new Object[] {wrapped});
//code after method call
}
}
Метод в test.Runner
классе, который вызывает logStuff
public static void main(String[] args) {
Object instance = "thats a string";
System.out.println("Obj type : " + instance.getClass());
YourType.logStuff(instance);
System.out.println("Obj type : " + instance.getClass());
}
Вывод:
Obj type : class java.lang.String
Not a string DummyContainer=[clazz: class java.lang.String, string: thats a string]
Obj type : class java.lang.String
Для построения проекта я использую Maven. Вот как выглядит раздел сборки моего pom.xml
:
...
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.11</version>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.13</version>
</dependency>
</dependencies>
<configuration>
<Xajruntimetarget>1.8</Xajruntimetarget>
<complianceLevel>1.8</complianceLevel>
<weaveDependencies>
<weaveDependency>
<groupId>your.jar.group.id</groupId>
<artifactId>artifactid</artifactId>
</weaveDependency>
</weaveDependencies>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
...