• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*******************************************************************************
2  * Copyright (c) 2009, 2021 Mountainminds GmbH & Co. KG and Contributors
3  * This program and the accompanying materials are made available under
4  * the terms of the Eclipse Public License 2.0 which is available at
5  * http://www.eclipse.org/legal/epl-2.0
6  *
7  * SPDX-License-Identifier: EPL-2.0
8  *
9  * Contributors:
10  *    Evgeny Mandrikov - initial API and implementation
11  *
12  *******************************************************************************/
13 package org.jacoco.core.test;
14 
15 import java.io.IOException;
16 
17 import org.jacoco.core.data.ExecutionDataStore;
18 import org.jacoco.core.data.SessionInfoStore;
19 import org.jacoco.core.instr.Instrumenter;
20 import org.jacoco.core.runtime.IRuntime;
21 import org.jacoco.core.runtime.RuntimeData;
22 import org.jacoco.core.runtime.SystemPropertiesRuntime;
23 
24 /**
25  * Class loader which loads classes from another class loader and instruments
26  * them.
27  */
28 public final class InstrumentingLoader extends ClassLoader {
29 
30 	private final IRuntime runtime;
31 	private final String scope;
32 	private final ClassLoader delegate;
33 
34 	private final RuntimeData data;
35 	private final Instrumenter instrumenter;
36 
InstrumentingLoader(IRuntime runtime, String scope, ClassLoader delegate)37 	public InstrumentingLoader(IRuntime runtime, String scope,
38 			ClassLoader delegate) throws Exception {
39 		this.runtime = runtime;
40 		this.scope = scope;
41 		this.delegate = delegate;
42 		this.data = new RuntimeData();
43 		runtime.startup(data);
44 		this.instrumenter = new Instrumenter(runtime);
45 	}
46 
InstrumentingLoader(Class<?> target)47 	public InstrumentingLoader(Class<?> target) throws Exception {
48 		this(new SystemPropertiesRuntime(), target.getPackage().getName(),
49 				target.getClassLoader());
50 	}
51 
52 	@Override
loadClass(String name, boolean resolve)53 	protected synchronized Class<?> loadClass(String name, boolean resolve)
54 			throws ClassNotFoundException {
55 		if (name.startsWith(scope)) {
56 			Class<?> c = findLoadedClass(name);
57 			if (c != null) {
58 				return c;
59 			}
60 			final byte[] bytes;
61 			try {
62 				bytes = TargetLoader.getClassDataAsBytes(delegate, name);
63 			} catch (IOException e) {
64 				throw new ClassNotFoundException("Unable to load", e);
65 			}
66 			final byte[] instrumented;
67 			try {
68 				instrumented = instrumenter.instrument(bytes, name);
69 			} catch (IOException e) {
70 				throw new ClassNotFoundException("Unable to instrument", e);
71 			}
72 			c = defineClass(name, instrumented, 0, instrumented.length);
73 			if (resolve) {
74 				resolveClass(c);
75 			}
76 			return c;
77 		}
78 		return super.loadClass(name, resolve);
79 	}
80 
collect()81 	public ExecutionDataStore collect() {
82 		final ExecutionDataStore store = new ExecutionDataStore();
83 		data.collect(store, new SessionInfoStore(), false);
84 		runtime.shutdown();
85 		return store;
86 	}
87 
88 }
89