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