aboutsummaryrefslogtreecommitdiffstats
path: root/org.jacoco.core.test/src/org/jacoco/core/test/InstrumentingLoader.java
blob: a870267e5de77312cd15903d7a5fc1a2afd6e1ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/*******************************************************************************
 * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Evgeny Mandrikov - initial API and implementation
 *
 *******************************************************************************/
package org.jacoco.core.test;

import java.io.IOException;

import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.data.SessionInfoStore;
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.IRuntime;
import org.jacoco.core.runtime.RuntimeData;
import org.jacoco.core.runtime.SystemPropertiesRuntime;

/**
 * Class loader which loads classes from another class loader and instruments
 * them.
 */
public final class InstrumentingLoader extends ClassLoader {

	private final IRuntime runtime;
	private final String scope;
	private final ClassLoader delegate;

	private final RuntimeData data;
	private final Instrumenter instrumenter;

	public InstrumentingLoader(IRuntime runtime, String scope,
			ClassLoader delegate) throws Exception {
		this.runtime = runtime;
		this.scope = scope;
		this.delegate = delegate;
		this.data = new RuntimeData();
		runtime.startup(data);
		this.instrumenter = new Instrumenter(runtime);
	}

	public InstrumentingLoader(Class<?> target) throws Exception {
		this(new SystemPropertiesRuntime(), target.getPackage().getName(),
				target.getClassLoader());
	}

	@Override
	protected synchronized Class<?> loadClass(String name, boolean resolve)
			throws ClassNotFoundException {
		if (name.startsWith(scope)) {
			final byte[] bytes;
			try {
				bytes = TargetLoader.getClassDataAsBytes(delegate, name);
			} catch (IOException e) {
				throw new ClassNotFoundException("Unable to load", e);
			}
			final byte[] instrumented;
			try {
				instrumented = instrumenter.instrument(bytes, name);
			} catch (IOException e) {
				throw new ClassNotFoundException("Unable to instrument", e);
			}
			final Class<?> c = defineClass(name, instrumented, 0,
					instrumented.length);
			if (resolve) {
				resolveClass(c);
			}
			return c;
		}
		return super.loadClass(name, resolve);
	}

	public ExecutionDataStore collect() {
		final ExecutionDataStore store = new ExecutionDataStore();
		data.collect(store, new SessionInfoStore(), false);
		runtime.shutdown();
		return store;
	}

}