pax_global_header00006660000000000000000000000064121765217560014526gustar00rootroot0000000000000052 comment=ab226299d723d8c5a0a4772513e2a53fb6c42155 constant-pool-scanner-constant-pool-scanner-1.2/000077500000000000000000000000001217652175600220445ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/.gitignore000066400000000000000000000000071217652175600240310ustar00rootroot00000000000000target constant-pool-scanner-constant-pool-scanner-1.2/README.md000066400000000000000000000001201217652175600233140ustar00rootroot00000000000000Simple utility to scan Java bytecode for class references in the constant pool. constant-pool-scanner-constant-pool-scanner-1.2/pom.xml000066400000000000000000000042341217652175600233640ustar00rootroot00000000000000 4.0.0 org.sonatype.oss oss-parent 7 org.jenkins-ci constant-pool-scanner 1.2 jar Constant Pool Scanner Simple utility to scan Java bytecode for class references in the constant pool. https://github.com/jenkinsci/constant-pool-scanner NetBeans CDDL/GPL http://www.netbeans.org/cddl-gplv2.html jglick Jesse Glick jglick@cloudbees.com scm:git:git@github.com:jenkinsci/constant-pool-scanner.git scm:git:git@github.com:jenkinsci/constant-pool-scanner.git git@github.com:jenkinsci/constant-pool-scanner.git UTF-8 junit junit 4.11 test org.apache.commons commons-io 1.3.2 test com.github.stephenc.findbugs findbugs-annotations 1.3.9-1 provided constant-pool-scanner-constant-pool-scanner-1.2/src/000077500000000000000000000000001217652175600226335ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/000077500000000000000000000000001217652175600235575ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/000077500000000000000000000000001217652175600245005ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/000077500000000000000000000000001217652175600252675ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/000077500000000000000000000000001217652175600272445ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scanner/000077500000000000000000000000001217652175600336375ustar00rootroot00000000000000ClassConstant.java000066400000000000000000000010401217652175600371750ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; /** * Constant that refers to a class name. * * @author Kohsuke Kawaguchi */ public final class ClassConstant { private Utf8Constant value; /** * UTF-8 constant that holds the class' internal name. */ public Utf8Constant getUTF8() { return value; } /** * Gets the actual class name. */ public String get() { return getUTF8().get(); } ClassConstant set(Utf8Constant v) { this.value = v; return this; } } ConstantPool.java000066400000000000000000000053311217652175600370500ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; import java.util.Arrays; import java.util.Iterator; /** * Parsed constants. * * @author Kohsuke Kawaguchi */ public final class ConstantPool { final Object[] constants; ConstantPool(int size) { this.constants = new Object[size]; } /** * Lists up all the constants of the specified type (including subtypes if applicable.) */ public Iterable list(final Class type) { return new Iterable() { public Iterator iterator() { return new Iterator() { int idx=-1; { seek(); } public boolean hasNext() { return idxoriginal sources */ public class ConstantPoolScanner { /** * Examines the constant pool of a class file and looks for references to other classes. * @param data a Java class file * @return a (sorted) set of binary class names (e.g. {@code some.pkg.Outer$Inner}) * @throws IOException in case of malformed bytecode */ public static Set dependencies(byte[] data) throws IOException { return dependencies(new ByteArrayInputStream(data)); } /** * Examines the constant pool of a class file and looks for references to other classes. * @param in Stream that reads a Java class file * @return a (sorted) set of binary class names (e.g. {@code some.pkg.Outer$Inner}) * @throws IOException in case of malformed bytecode */ public static Set dependencies(InputStream in) throws IOException { ConstantPool pool = parse(in,CLASS,NAME_AND_TYPE); Set result = new TreeSet(); for (ClassConstant cc : pool.list(ClassConstant.class)) { String s = cc.get(); while (s.charAt(0) == '[') { // array type s = s.substring(1); } if (s.length() == 1) { // primitive continue; } String c; if (s.charAt(s.length() - 1) == ';' && s.charAt(0) == 'L') { // Uncommon but seems sometimes this happens. c = s.substring(1, s.length() - 1); } else { c = s; } result.add(c.replace('/', '.')); } for (NameAndTypeConstant cc : pool.list(NameAndTypeConstant.class)) { String s = cc.getDescriptor(); int idx = 0; while ((idx = s.indexOf('L', idx)) != -1) { int semi = s.indexOf(';', idx); if (semi == -1) { throw new IOException("Invalid type or descriptor: " + s); } result.add(s.substring(idx + 1, semi).replace('/', '.')); idx = semi; } } return result; } private ConstantPoolScanner() { } /** * Parses a class file and invokes the visitor with constants. */ public static ConstantPool parse(byte[] source, ConstantType... types) throws IOException { return parse(new ByteArrayInputStream(source),types); } /** * Parses a class file and invokes the visitor with constants. */ public static ConstantPool parse(InputStream source, ConstantType... types) throws IOException { return parse(new DataInputStream(source),Arrays.asList(types)); } /** * Parses a class file and invokes the visitor with constants. */ public static ConstantPool parse(DataInput s, Collection _collect) throws IOException { skip(s,8); // magic, minor_version, major_version int size = s.readUnsignedShort() - 1; // constantPoolCount ConstantPool pool = new ConstantPool(size); // figure out all the types of constants we need to collect final EnumSet collect = transitiveClosureOf(_collect); for (int i = 0; i < size; i++) { int tag = s.readByte(); switch (tag) { case 1: // CONSTANT_Utf8 if (collect.contains(UTF8)) pool.utf8At(i).actual = s.readUTF(); else skip(s,s.readUnsignedShort()); break; case 7: // CONSTANT_Class if (collect.contains(CLASS)) pool.classAt(i).set(pool.utf8At(readIndex(s))); else skip(s,2); break; case 3: // CONSTANT_Integer if (collect.contains(INTEGER)) pool.set(i,s.readInt()); else skip(s,4); break; case 4: // CONSTANT_Float if (collect.contains(FLOAT)) pool.set(i,s.readFloat()); else skip(s,4); break; case 9: // CONSTANT_Fieldref if (collect.contains(FIELD_REF)) pool.fieldRefAt(i).set(pool.classAt(readIndex(s)),pool.nameAndTypeAt(readIndex(s))); else skip(s,4); break; case 10: // CONSTANT_Methodref if (collect.contains(METHOD_REF)) pool.methodRefAt(i).set(pool.classAt(readIndex(s)),pool.nameAndTypeAt(readIndex(s))); else skip(s,4); break; case 11: // CONSTANT_InterfaceMethodref if (collect.contains(INTERFACE_METHOD_REF)) pool.interfaceMethodRefAt(i).set(pool.classAt(readIndex(s)),pool.nameAndTypeAt(readIndex(s))); else skip(s,4); break; case 12: // CONSTANT_NameAndType if (collect.contains(NAME_AND_TYPE)) pool.nameAndTypeAt(i).set(pool.utf8At(readIndex(s)),pool.utf8At(readIndex(s))); else skip(s,4); break; case 8: // CONSTANT_String if (collect.contains(STRING)) pool.set(i, new StringConstant(pool.utf8At(readIndex(s)))); else skip(s,2); break; case 5: // CONSTANT_Long if (collect.contains(LONG)) pool.set(i,s.readLong()); else skip(s,8); i++; // weirdness in spec break; case 6: // CONSTANT_Double if (collect.contains(DOUBLE)) pool.set(i,s.readDouble()); else skip(s,8); i++; // weirdness in spec break; case 15:// CONSTANT_MethodHandle skip(s,3); break; case 16:// CONSTANT_MethodType skip(s,2); break; case 18:// CONSTANT_INVOKE_DYNAMIC skip(s,4); break; default: throw new IOException("Unrecognized constant pool tag " + tag + " at index " + i + "; running constants: " + pool); } } return pool; } private static EnumSet transitiveClosureOf(Collection collect) { EnumSet subject = EnumSet.copyOf(collect); for (ConstantType c : collect) { subject.addAll(c.implies); } return subject; } private static void skip(DataInput source, int bytes) throws IOException { // skipBytes cannot be used reliably because 0 is a valid return value // and we can end up looping forever source.readFully(new byte[bytes]); } private static int readIndex(DataInput source) throws IOException { return source.readUnsignedShort() - 1; } } ConstantType.java000066400000000000000000000030211217652175600370520ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; import java.util.Arrays; import java.util.List; /** * Types of constants. * * @author Kohsuke Kawaguchi */ public enum ConstantType { UTF8(1,Utf8Constant.class), CLASS(7,ClassConstant.class,UTF8), NAME_AND_TYPE(12,NameAndTypeConstant.class,UTF8), FIELD_REF(9,FieldRefConstant.class,CLASS,NAME_AND_TYPE,UTF8), METHOD_REF(10,MethodRefConstant.class,CLASS,NAME_AND_TYPE,UTF8), INTERFACE_METHOD_REF(11,InterfaceMethodRefConstant.class,CLASS,NAME_AND_TYPE,UTF8), STRING(8,String.class,UTF8), INTEGER(3,Integer.class), FLOAT(4,Float.class), LONG(5,Long.class), DOUBLE(6,Double.class), // METHOD_HANDLE(15, // METHOD_TYPE(16, // INVOKE_DYNAMIC(18 ; /** * The type of the constant object this kind will produce. */ public final Class valueType; /** * Collection of this type of constant requires collecting them as well. * The set is transitive. */ final List implies; /** * Constant pool tag */ public final int tag; ConstantType(int tag, Class valueType, ConstantType... implies) { this.tag = tag; this.valueType = valueType; this.implies = Arrays.asList(implies); } private static final ConstantType[] byTag = new ConstantType[20]; static { for (ConstantType c : ConstantType.values()) { byTag[c.tag] = c; } } public static ConstantType fromTag(int tag) { return byTag[tag]; } } FieldRefConstant.java000066400000000000000000000003021217652175600376100ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; /** * Reference to a field of another class. * * @author Kohsuke Kawaguchi */ public final class FieldRefConstant extends MemberRefConstant { } InterfaceMethodRefConstant.java000066400000000000000000000003561217652175600416370ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; /** * Reference to an interface's method for which a method handle is to be created. * * @author Kohsuke Kawaguchi */ public class InterfaceMethodRefConstant extends MemberRefConstant { } MemberRefConstant.java000066400000000000000000000022551217652175600400050ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; /** * Reference to a field/method of another class. * * @author Kohsuke Kawaguchi */ public abstract class MemberRefConstant { ClassConstant clazz; NameAndTypeConstant nameAndType; /** * Gets the internal name of the class that contains method/field in question. */ public String getClazz() { return clazz.get(); } /** * Class that contains the method/field in question. */ public ClassConstant getClassConstant() { return clazz; } /** * Name of the field/method. */ public String getName() { return nameAndType.getName(); } /** * Its type descriptor, a combination of field/method return type and parameter types. */ public String getDescriptor() { return nameAndType.getDescriptor(); } /** * Signature of the method/field. */ public NameAndTypeConstant getNameAndTypeConstant() { return nameAndType; } MemberRefConstant set(ClassConstant clazz, NameAndTypeConstant nameAndType) { this.clazz = clazz; this.nameAndType = nameAndType; return this; } } MethodRefConstant.java000066400000000000000000000003041217652175600400070ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; /** * Reference to a method in another class. * * @author Kohsuke Kawaguchi */ public final class MethodRefConstant extends MemberRefConstant { } NameAndTypeConstant.java000066400000000000000000000017011217652175600403010ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; /** * Name of a field/method plus its descriptor. * * @author Kohsuke Kawaguchi */ public final class NameAndTypeConstant { private Utf8Constant name; private Utf8Constant descriptor; /** * Name of the field/method. */ public String getName() { return name.get(); } public Utf8Constant getNameUTF8() { return name; } /** * Its type descriptor, a combination of field/method return type and parameter types. */ public String getDescriptor() { return descriptor.get(); } /** * Its type descriptor, a combination of field/method return type and parameter types. */ public Utf8Constant getDescriptorUTF8() { return descriptor; } NameAndTypeConstant set(Utf8Constant name, Utf8Constant descriptor) { this.name = name; this.descriptor = descriptor; return this; } } StringConstant.java000066400000000000000000000005541217652175600374070ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; /** * String constant (which is separate from UTF-8 constant.) * * @author Kohsuke Kawaguchi */ public final class StringConstant { private final Utf8Constant actual; StringConstant(Utf8Constant actual) { this.actual = actual; } public String get() { return actual.get(); } } Utf8Constant.java000066400000000000000000000011311217652175600367570ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/main/java/org/jenkinsci/constant_pool_scannerpackage org.jenkinsci.constant_pool_scanner; /** * UTF-8 Constant (which is separate from string constant.) * * @author Kohsuke Kawaguchi */ public final class Utf8Constant implements CharSequence { String actual; public String get() { return actual; } public int length() { return get().length(); } public char charAt(int index) { return get().charAt(index); } public String subSequence(int start, int end) { return get().substring(start,end); } @Override public String toString() { return actual; } } constant-pool-scanner-constant-pool-scanner-1.2/src/test/000077500000000000000000000000001217652175600236125ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/000077500000000000000000000000001217652175600245335ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/org/000077500000000000000000000000001217652175600253225ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/org/jenkinsci/000077500000000000000000000000001217652175600272775ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/org/jenkinsci/constant_pool_scanner/000077500000000000000000000000001217652175600336725ustar00rootroot00000000000000ConstantPoolScannerTest.java000066400000000000000000000064201217652175600412550ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/org/jenkinsci/constant_pool_scanner/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 Jesse Glick. All rights reserved. * * Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common * Development and Distribution License("CDDL") (collectively, the * "License"). You may not use this file except in compliance with the * License. You can obtain a copy of the License at * http://www.netbeans.org/cddl-gplv2.html * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the * specific language governing permissions and limitations under the * License. When distributing the software, include this License Header * Notice in each file and include the License file at * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the GPL Version 2 section of the License file that * accompanied this code. If applicable, add the following below the * License Header, with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. * */ package org.jenkinsci.constant_pool_scanner; import org.jenkinsci.constant_pool_scanner.samples.D; import org.jenkinsci.constant_pool_scanner.samples.C; import org.jenkinsci.constant_pool_scanner.samples.A; import org.jenkinsci.constant_pool_scanner.samples.B; import java.io.IOException; import java.util.Set; import java.util.TreeSet; import org.apache.commons.io.IOUtils; import static org.junit.Assert.*; import org.junit.Test; public class ConstantPoolScannerTest { @Test public void basics() throws Exception { assertDependencies(A.class, Object.class); assertDependencies(B.class, A.class); assertDependencies(C.class, Object.class); assertDependencies(D.class, Object.class, A.class, B.class, C.class, String.class); } private static void assertDependencies(Class from, Class... to) throws IOException { Set expected = new TreeSet(); for (Class c : to) { expected.add(c.getName()); } expected.add(from.getName()); byte[] bytecode = IOUtils.toByteArray(from.getClassLoader().getResourceAsStream(from.getName().replace('.', '/') + ".class")); Set actual = ConstantPoolScanner.dependencies(bytecode); assertEquals(expected.toString(), actual.toString()); } } 000077500000000000000000000000001217652175600352575ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/org/jenkinsci/constant_pool_scanner/samplesA.java000066400000000000000000000001101217652175600362720ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/org/jenkinsci/constant_pool_scanner/samplespackage org.jenkinsci.constant_pool_scanner.samples; public class A {} B.java000066400000000000000000000001221217652175600362760ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/org/jenkinsci/constant_pool_scanner/samplespackage org.jenkinsci.constant_pool_scanner.samples; public class B extends A {} C.java000066400000000000000000000001401217652175600362770ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/org/jenkinsci/constant_pool_scanner/samplespackage org.jenkinsci.constant_pool_scanner.samples; public interface C { String m(A x); } D.java000066400000000000000000000004171217652175600363070ustar00rootroot00000000000000constant-pool-scanner-constant-pool-scanner-1.2/src/test/java/org/jenkinsci/constant_pool_scanner/samplespackage org.jenkinsci.constant_pool_scanner.samples; import edu.umd.cs.findbugs.annotations.SuppressWarnings; @SuppressWarnings({"NP_LOAD_OF_KNOWN_NULL_VALUE", "NP_ALWAYS_NULL"}) public class D { { A a = new B(); C c = null; c.m(a); } }