Hi,

the memory class loader is a very simple implementation for a single class. If you want to load multiple classes or even redefine them within the JVM this takes a little more considerations. I recommend to first get a very good understanding about class loading and class lifecycle.

My question is why do you want to do this at all? The JaCoCo agent transparently instruments any class loaded by the JVM. Even those classes which are created or redefined on the fly. It even offers a runtime API to fetch execution data from within the JVM:

http://www.eclemma.org/jacoco/trunk/doc/api/org/jacoco/agent/rt/package-summary.html

Best regards,
-marc


On 17.10.14 08:14, [email protected] wrote:
Hi,
We are trying to integrate jacoco with our faultlocalization tool,
following your usage API example CoreTutorial.java.
Means we initilize a MemoryClassloader in which instrumented classes are 
redefined, then load classes from that classloader to execute in order for 
jacoco to be able to analyze.
It seems okay when we test a simple program, but for a quite more complicated 
one, we get an error about classloader.

This is the stacktrace:
java.lang.LinkageError: loader constraint violation: loader (instance of 
sun/misc/Launcher$AppClassLoader)
previously initiated loading for a different type with name 
"de/susebox/jtopas/PluginTokenizer"
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
        at 
java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
        at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
        at java.lang.Class.getDeclaredMethods0(Native Method)
        at java.lang.Class.privateGetDeclaredMethods(Class.java:2427)
        at java.lang.Class.privateGetPublicMethods(Class.java:2547)
        at java.lang.Class.privateGetPublicMethods(Class.java:2557)
        at java.lang.Class.privateGetPublicMethods(Class.java:2557)
        at java.lang.Class.getMethods(Class.java:1410)
        at 
codecoverage.jacoco.JavaCoCo.extractTestCasesAsRequests(JavaCoCo.java:56)
        at codecoverage.jacoco.JavaCoCo.run(JavaCoCo.java:107)

It looks like class "PluginTokenizer" was already loaded (and redefined) by 
MemoryClassloader, then by AppClassLoader, that cause violation.
Here are our classes: (I shortened by removing some unrelated lines)

45 public class JavaCoCo implements ICodeCoverage {
46      private Logger<?> logger = Logger.getDefaultLogger();
47      private static final String JUNIT_TEST_METHOD_PREFIX = "test";
48      private static final String JUNIT_TEST_SUITE_PREFIX = "suite";
49      private MemoryClassLoader memoryClassLoader;
50      
51      private List<Request> extractTestCasesAsRequests(
52                      List<String> junitClassNames) throws 
ClassNotFoundException {
53              ArrayList<Request> requests = new ArrayList<Request>();
54              for (String className : junitClassNames) {
55                      Class<?> junitClass = 
memoryClassLoader.loadClass(className);
56                      Method[] methods = junitClass.getMethods();
57                      for (Method method : methods) {
58                              Test test = method.getAnnotation(Test.class);
59                              if (test != null) {
63                                      Request request = 
Request.method(junitClass, method.getName());
64                                      requests.add(request);
65                              }
66                      }
67              }
68              return requests;
69      }
70
71      public void run(ICoverageReport report, List<String> testingClassNames,
72                      List<String> junitClassNames) throws Exception {
73              report.setTestingClassNames(testingClassNames);
74              List<String> classNameForJaCoco = new 
ArrayList<String>(testingClassNames);
75              classNameForJaCoco.addAll(junitClassNames);
76              
77              // For instrumentation and runtime we need a IRuntime instance
78              // to collect execution data:
79              final IRuntime runtime = new LoggerRuntime();
80              
81              memoryClassLoader = new MemoryClassLoader();
83              // The Instrumenter creates a modified version of our test 
target class
84              // that contains additional probes for execution data recording:
85              final Instrumenter instr = new Instrumenter(runtime);
86              ArrayList<byte[]> instrumenteds = new ArrayList<byte[]>();
87              
88              for(String clazz: classNameForJaCoco){
89                      try {
90                              
instrumenteds.add(instr.instrument(getTargetClass(clazz), clazz));
91                      } catch (IOException e) {
92                              logger.logEx(e, "cannot load class " + clazz);
93                              throw e;
94                      }
95              }
96              
97              for(int j = 0; j < classNameForJaCoco.size(); j++){
98                      String testingClassName = classNameForJaCoco.get(j);
99                      memoryClassLoader.addDefinition(testingClassName, 
instrumenteds.get(j));
100             }
101             
102             // Now we're ready to run our instrumented class and need to 
startup the
103             // runtime first:
104             final RuntimeData data = new RuntimeData();
105             runtime.startup(data);
106             
107             List<Request> testcases = 
extractTestCasesAsRequests(junitClassNames);
108             for(int i = 0; i < testcases.size(); i++){
109                     Request testcase = testcases.get(i);
110                     
111                     data.reset();
112                     final Class<?> targetClass = 
memoryClassLoader.loadClass(RequestExecution.class.getName());
113
114                     // Here we execute our test target class through its 
Runnable interface:
115                     final Runnable targetInstance = (Runnable) 
targetClass.newInstance();
116                     
117                     Method setRequest = targetClass.getMethod("setRequest", 
Request.class);
118                     setRequest.invoke(targetInstance, testcase);
119                     
120                     targetInstance.run();
121                     
122                     /* Extract the test's running result */
123                     Method getResult = targetClass.getMethod("getResult");
124                     boolean isPassed = (Boolean) 
getResult.invoke(targetInstance);
125                     List<Failure> failures = 
RequestExecution.getFailureTrace(
126                                     targetClass, targetInstance);
127                     report.addFailureTrace(extractBrkpsFromTrace(failures,
128                                     testingClassNames));
129
130                     // At the end of test execution we collect execution 
data and shutdown
131                     // the runtime:
132                     final ExecutionDataStore executionData = new 
ExecutionDataStore();
133                     final SessionInfoStore sessionInfos = new 
SessionInfoStore();
134                     data.collect(executionData, sessionInfos, false);
135
136                     // Together with the original class definition we can 
calculate coverage
137                     // information:
138                     final CoverageBuilder coverageBuilder = new 
CoverageBuilder();
139                     final Analyzer analyzer = new Analyzer(executionData, 
coverageBuilder);
140                     for(String testingClassName: testingClassNames){
141                             
analyzer.analyzeClass(getTargetClass(testingClassName), testingClassName);
142                     }
143                     
144                     // Let's dump some metrics and line coverage 
information:
145                     for (final IClassCoverage cc : 
coverageBuilder.getClasses()) {
146                             // do not display data for junit test file
147                             
161                     }
162             }
163             runtime.shutdown();
164     }

191 }

MemoryClassLoader:

9 public class MemoryClassLoader extends ClassLoader {
10
11      private final Map<String, byte[]> definitions = new HashMap<String, 
byte[]>();
12
13      public MemoryClassLoader(ClassLoader parent) {
14              super(parent);
15      }
16      
17      public MemoryClassLoader () {
18              
19      }

29      public void addDefinition(final String name, final byte[] bytes) {
30              definitions.put(name, bytes);
31      }
32
33      @Override
34      protected Class<?> loadClass(final String name, final boolean resolve)
35                      throws ClassNotFoundException {
36              final byte[] bytes = definitions.get(name);
37              if (bytes != null) {
38                      Class<?> result = defineClass(name, bytes, 0, 
bytes.length);
39                      // prevent defining class second time.
40                      definitions.remove(name);
41                      return result;
42              }
43              return super.loadClass(name, resolve);
44      }
45 }

RequestExecution is a runnable class to execute a junit method as a request.
input of the program:
testingClassNames:
"de.susebox.java.io.ExtIOException",
"de.susebox.java.lang.ExtIndexOutOfBoundsException",
"de.susebox.java.util.InputStreamTokenizer",
"de.susebox.jtopas.PluginTokenizer"

junitClassNames:
"de.susebox.java.util.TestTokenizerProperties",
"de.susebox.java.util.TestTokenProperties",
"de.susebox.java.util.TestInputStreamTokenizer",
"de.susebox.java.util.TestDifficultSituations",
"de.susebox.jtopas.TestPluginTokenizer",
"de.susebox.jtopas.TestTokenizerSpeed"

In this test, PluginTokenizer is called in both TestPluginTokenizer, and 
TestTokenizerSpeed

Do you have any idea about the problem and how to fix it?
Let me know if you need any more information.
Thanks in advance for the help,
lyly


--
You received this message because you are subscribed to the Google Groups "JaCoCo 
and EclEmma Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to