Ich erstelle einen Java-Agenten, mit dem einige Bytecode-Änderungen an einigen Klassen vorgenommen werden. org.eclipse.jdt.core.JDTCompilerAdapter
ist einer davon. Ich verwende javassit, um einige der execute()
Methode von org.eclipse.jdt.core.JDTCompilerAdapter
zu ändern. So habe ich eingeschlossen ecj wie in meinem Agenten Projekt (mit gradle)Klasse org.eclipse.jdt.core.JDTCompilerAdapter konnte wegen einer ungültigen Abhängigkeit nicht geladen werden
compile group: 'org.eclipse.jdt.core.compiler' ,name: 'ecj', version :'4.3.1'
Wie ich aus ecj einige Klassen verwenden müssen.
Das Ziel des Agenten ist es, die Aufrufe zur Ausführung der Methode abzufangen, die Methode execute zu modifizieren, um einige meiner Klassen in einige Aufrufe einzufügen, um eine Verarbeitung auszulösen.
Ich teste den Agenten gegen ein einfaches Java-Projekt mit 2 Klassen. Das Projekt ist mit Ant gebaut und verwendet JDTCompilerAdapter
als Compiler. Hier
ist die Datei build.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="build" name="TestProject">
<property file="build.properties" />
<property name="debuglevel" value="source,lines,vars"/>
<property name="target" value="1.7"/>
<property name="source" value="1.7"/>
<path id="PClasspath">
<pathelement location="bin"/>
</path>
<target name="init">
<mkdir dir="bin"/>
<copy includeemptydirs="false" todir="bin">
<fileset dir="src">
<exclude name="**/*.java"/>
</fileset>
</copy>
</target>
<target name="clean">
<delete dir="bin"/>
</target>
<target depends="clean" name="cleanall"/>
<target depends="init" name="build">
<javac debug="true" debuglevel="${debuglevel}" destdir="bin" includeantruntime="false" source="${source}" target="${target}">
<src path="src"/>
<classpath refid="PClasspath"/>
</javac>
</target>
<!--
<target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler">
<copy todir="${ant.library.dir}">
<fileset dir="${ECLIPSE_JDT_CORE}" includes="*.jar"/>
</copy>
</target>-->
<target name="build-e" >
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
<antcall target="build"/>
</target>
Der Agent verwendet werden soll, wenn ein Projekt zu bauen. Also das Mittel zum Testen verwende ich diesen Befehl ein:
java -jar agent-wrapper.jar --outdir ./out --exec ./build_wrapper.sh
build_wrapper.sh diese enthält (Ich habe ecj Abhängigkeit hinzugefügt, so konnte ich das Projekt mit JDTCompilerAdapter
kompilieren, wie ich in bulid.xml haben <property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
:
../ant/bin/ant -lib ../eclipse/plugins/ecj-4.3.1.jar build-e
Die Idee ist, dass der Agent-Wrapper das Argument analysieren wird (outdir wird verwendet, um einige Sachen zu generieren und exec ist ein Skript, um den Build meines Testprojekts zu starten) den Befehl aus build_wrapper.sh
(in diesem case ../ant/bin/ant -lib ../eclipse/plugins/ecj-4.3.1.jar build-e
) und fügen Sie es selbst als Java-Agent zum Befehl hinzu.
Das Problem tritt während der Ausführung des Agenten auf. Hier ist die Ausgabe:
java -jar custom-agent.jar --outdir ./out --exec ./build_wrapper.sh [10:18:53]
Picked up JAVA_TOOL_OPTIONS: -javaagent:/Users/dev/TestAgent/project/custom-agent.jar=OUTDIR=/Users/dev/TestAgent/project/./out
objc[30474]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/jre/bin/java and /Library/Java/JavaVirtualMachines/jdk1.7.0_51.jdk/Contents/Home/jre/lib/libinstrument.dylib. One of the two will be used. Which one is undefined.
Buildfile: /Users/dev/TestAgent/project/build.xml
build-e:
init:
[mkdir] Created dir: /Users/dev/TestAgent/project/bin
build:
BUILD FAILED
/Users/dev/TestAgent/project/build.xml:47: The following error occurred while executing this line:
/Users/dev/TestAgent/project/build.xml:32: Class org.eclipse.jdt.core.JDTCompilerAdapter could not be loaded because of an invalid dependency.
Total time: 2 seconds
abnormal termination, exit code: 1
Wenn ich nicht ecj-4.3.1.jar in meinem Agenten Projekt verwenden, das Build läuft gut abfangen ich den Anruf zu execute()
Methode, aber ich kann nicht die anderen Klassen verwenden aus ecj jar.
Bitte schauen Sie, ob dieser Link hilft. Gemäß diesem Link könnte es einen Klassenpfadkonflikt geben. https://www.liveray.com/community/forums/-/message_boards/message/43851128 – Rao