diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandler.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandler.java index b65e716c0..e0f156f73 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandler.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classloading/PlainClassLoaderHandler.java @@ -30,7 +30,6 @@ import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; @@ -153,15 +152,23 @@ public class PlainClassLoaderHandler implements ClassInjector { } - private InputStream getInputStream(ClassLoader classLoader, String className) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { + private InputStream getInputStream(ClassLoader classLoader, String classPath) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException { if (isDebug) { - logger.debug("Get input stream className:{} cl:{}", className, classLoader); + logger.debug("Get input stream className:{} cl:{}", classPath, classLoader); } final String pluginJarPath = pluginConfig.getPluginJarURLExternalForm(); final ClassLoaderAttachment attachment = getClassLoaderAttachment(classLoader, pluginJarPath); - final InputStream inputStream = attachment.getInputStream(className); - return inputStream; + try { + return pluginJarReader.getInputStream(classPath); + } catch(Exception ex) { + if (isDebug) { + logger.debug("Failed to read plugin jar: {}", pluginConfig.getPluginJarURLExternalForm(), ex); + } + } + + // not found. + return null; } private ClassLoaderAttachment getClassLoaderAttachment(ClassLoader classLoader, final String pluginJarPath) { @@ -291,9 +298,7 @@ public class PlainClassLoaderHandler implements ClassInjector { } final Class clazz = defineClass(classLoader, currentClass); - currentClass.setDefinedClass(clazz); - attachment.putClass(currentClass.getClassName(), currentClass); - + attachment.putClass(currentClass.getClassName(), clazz); } private Class defineClass(ClassLoader classLoader, SimpleClassMetadata classMetadata) { @@ -343,7 +348,7 @@ public class PlainClassLoaderHandler implements ClassInjector { private final ConcurrentMap pluginLock = new ConcurrentHashMap(); - private final ConcurrentMap classCache = new ConcurrentHashMap(); + private final ConcurrentMap> classCache = new ConcurrentHashMap>(); public PluginLock getPluginLock(String jarFile) { final PluginLock exist = this.pluginLock.get(jarFile); @@ -359,8 +364,8 @@ public class PlainClassLoaderHandler implements ClassInjector { return newPluginLock; } - public void putClass(String className, SimpleClassMetadata classMetadata) { - final SimpleClassMetadata duplicatedClass = this.classCache.putIfAbsent(className, classMetadata); + public void putClass(String className, Class clazz) { + final Class duplicatedClass = this.classCache.putIfAbsent(className, clazz); if (duplicatedClass != null) { if (logger.isWarnEnabled()) { logger.warn("duplicated pluginClass {}", className); @@ -369,27 +374,12 @@ public class PlainClassLoaderHandler implements ClassInjector { } public Class getClass(String className) { - final SimpleClassMetadata classMetadata = this.classCache.get(className); - if(classMetadata == null) { - return null; - } - - return classMetadata.getDefinedClass(); + return this.classCache.get(className); } public boolean containsClass(String className) { return this.classCache.containsKey(className); } - - public InputStream getInputStream(String className) { - final SimpleClassMetadata classMetadata = this.classCache.get(className); - if (classMetadata == null) { - return null; - } - - return new ByteArrayInputStream(classMetadata.getClassBinary()); - } - } private static class PluginLock { diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/AnnotationMetadataVisitor.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/AnnotationMetadataVisitor.java new file mode 100644 index 000000000..bd6d8cde9 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/AnnotationMetadataVisitor.java @@ -0,0 +1,52 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author jaehong.kim + */ +public class AnnotationMetadataVisitor extends ClassVisitor { + private final List annotationInternalNames = new ArrayList(); + + public AnnotationMetadataVisitor() { + super(Opcodes.ASM5); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + final Type type = Type.getType(desc); + if (type.getSort() == Type.OBJECT) { + final String internalName = type.getInternalName(); + if (internalName != null) { + this.annotationInternalNames.add(internalName); + } + } + + return null; + } + + public List getAnnotationInternalNames() { + return this.annotationInternalNames; + } +} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapper.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapper.java new file mode 100644 index 000000000..c79ed6f4e --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapper.java @@ -0,0 +1,98 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import com.navercorp.pinpoint.common.util.Asserts; +import org.objectweb.asm.ClassReader; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; + +/** + * @author jaehong.kim + */ +public class ClassReaderWrapper { + // wrapped ASM ClassReader. + private final ClassReader classReader; + + // bytecodes of the class. + public ClassReaderWrapper(final byte[] classBinary) { + Asserts.notNull(classBinary, "classBinary"); + this.classReader = new ClassReader(classBinary); + } + + // classloader and class internal name. + public ClassReaderWrapper(final ClassLoader classLoader, final String classInternalName) throws IOException { + Asserts.notNull(classInternalName, "classInternalName"); + ClassLoader cl = classLoader; + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + if (cl == null) { + // system fail. + throw new IOException("system classloader is null."); + } + } + + final InputStream in = cl.getResourceAsStream(classInternalName + ".class"); + if (in == null) { + throw new IOException("not found class. classLoader=" + cl + ", classInternalName=" + classInternalName); + } + + try { + this.classReader = new ClassReader(in); + } finally { + try { + in.close(); + } catch (IOException ignored) { + } + } + } + + // class's access flags. + public int getAccess() { + return this.classReader.getAccess(); + } + + // class version. + public int getVersion() { + return this.classReader.readShort(6); + } + + public String getSuperClassInternalName() { + return this.classReader.getSuperName(); + } + + public String getClassInternalName() { + return this.classReader.getClassName(); + } + + public List getInterfaceInternalNames() { + return Arrays.asList(this.classReader.getInterfaces()); + } + + public byte[] getClassBinary() { + return this.classReader.b; + } + + public List getAnnotationInternalNames() { + // annotation visitor. + final AnnotationMetadataVisitor annotationMetadataVisitor = new AnnotationMetadataVisitor(); + this.classReader.accept(annotationMetadataVisitor, 0); + return annotationMetadataVisitor.getAnnotationInternalNames(); + } +} diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadata.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadata.java new file mode 100644 index 000000000..c2d0f4583 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadata.java @@ -0,0 +1,66 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import java.util.Collections; +import java.util.List; + +/** + * @author jaehong.kim + */ +public class DefaultInternalClassMetadata implements InternalClassMetadata { + private final String classInternalName; + private final String superClassInternalName; + private final List interfaceInternalNames; + private final List annotationInternalNames; + + public DefaultInternalClassMetadata(final String classInternalName, final String superClassInternalName, final List interfaceInternalNames, final List annotationInternalNames) { + this.classInternalName = classInternalName; + this.superClassInternalName = superClassInternalName; + + if (interfaceInternalNames == null) { + this.interfaceInternalNames = Collections.EMPTY_LIST; + } else { + this.interfaceInternalNames = Collections.unmodifiableList(interfaceInternalNames); + } + + if (annotationInternalNames == null) { + this.annotationInternalNames = Collections.EMPTY_LIST; + } else { + this.annotationInternalNames = Collections.unmodifiableList(annotationInternalNames); + } + } + + @Override + public String getClassInternalName() { + return this.classInternalName; + } + + @Override + public String getSuperClassInternalName() { + return this.superClassInternalName; + } + + @Override + public List getInterfaceInternalNames() { + return this.interfaceInternalNames; + } + + @Override + public List getAnnotationInternalNames() { + return this.annotationInternalNames; + } +} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadata.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadata.java index 53a96d665..6ac357c61 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadata.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadata.java @@ -17,9 +17,9 @@ package com.navercorp.pinpoint.profiler.instrument.classreading; - import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import java.util.Collections; import java.util.List; /** @@ -36,18 +36,27 @@ public class DefaultSimpleClassMetadata implements SimpleClassMetadata { private final String superClassName; - private final List interfaceNameList; + private final List interfaceNames; private final byte[] classBinary; - private Class definedClass; - - public DefaultSimpleClassMetadata(int version, int accessFlag, String className, String superClassName, String[] interfaceNameList, byte[] classBinary) { + public DefaultSimpleClassMetadata(final int version, final int accessFlag, final String classInternalName, final String superClassInternalName, final List interfaceInternalNames, final byte[] classBinary) { this.version = version; this.accessFlag = accessFlag; - this.className = JavaAssistUtils.jvmNameToJavaName(className); - this.superClassName = JavaAssistUtils.jvmNameToJavaName(superClassName); - this.interfaceNameList = JavaAssistUtils.jvmNameToJavaName(interfaceNameList); + this.className = JavaAssistUtils.jvmNameToJavaName(classInternalName); + + if (superClassInternalName == null) { + this.superClassName = null; + } else { + this.superClassName = JavaAssistUtils.jvmNameToJavaName(superClassInternalName); + } + + if (interfaceInternalNames == null) { + this.interfaceNames = Collections.EMPTY_LIST; + } else { + this.interfaceNames = Collections.unmodifiableList(JavaAssistUtils.jvmNameToJavaName(interfaceInternalNames)); + } + this.classBinary = classBinary; } @@ -72,20 +81,11 @@ public class DefaultSimpleClassMetadata implements SimpleClassMetadata { @Override public List getInterfaceNames() { - return interfaceNameList; + return interfaceNames; } @Override public byte[] getClassBinary() { return classBinary; } - - public void setDefinedClass(final Class definedClass) { - this.definedClass = definedClass; - } - - @Override - public Class getDefinedClass() { - return this.definedClass; - } } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadata.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadata.java new file mode 100644 index 000000000..dff72d13f --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadata.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import java.util.List; + +/** + * @author jaehong.kim + */ +public interface InternalClassMetadata { + + // internal name of the class. + String getClassInternalName(); + + // internal name of the super class. + String getSuperClassInternalName(); + + // internal names of the class's interfaces. + List getInterfaceInternalNames(); + + // internal names of the class's annotations. + List getAnnotationInternalNames(); +} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReader.java new file mode 100644 index 000000000..15262df19 --- /dev/null +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReader.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import org.objectweb.asm.ClassReader; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +/** + * @author jaehong.kim + */ +public class InternalClassMetadataReader { + + private final InternalClassMetadata classMetadata; + + public static InternalClassMetadata readInternalClassMetadata(final byte[] classBinary) { + final InternalClassMetadataReader internalClassMetadataReader = new InternalClassMetadataReader(new ClassReaderWrapper(classBinary)); + return internalClassMetadataReader.getInternalClassMetadata(); + } + + public static InternalClassMetadata readInternalClassMetadata(final ClassLoader classLoader, final String classInternalName) throws IOException { + final InternalClassMetadataReader internalClassMetadataReader = new InternalClassMetadataReader(new ClassReaderWrapper(classLoader, classInternalName)); + return internalClassMetadataReader.getInternalClassMetadata(); + + } + + InternalClassMetadataReader(final ClassReaderWrapper classReader) { + this.classMetadata = new DefaultInternalClassMetadata(classReader.getClassInternalName(), classReader.getSuperClassInternalName(), classReader.getInterfaceInternalNames(), classReader.getAnnotationInternalNames()); + } + + public InternalClassMetadata getInternalClassMetadata() { + return classMetadata; + } +} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadata.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadata.java index e5bf6c1a6..169e303be 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadata.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadata.java @@ -35,8 +35,4 @@ public interface SimpleClassMetadata { List getInterfaceNames(); byte[] getClassBinary(); - - void setDefinedClass(Class definedClass); - - Class getDefinedClass(); -} +} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadataReader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadataReader.java index fe2270c00..4cd86f820 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadataReader.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadataReader.java @@ -17,8 +17,6 @@ package com.navercorp.pinpoint.profiler.instrument.classreading; -import org.objectweb.asm.ClassReader; - /** * @author Woonduk Kang(emeroad) */ @@ -26,34 +24,16 @@ public class SimpleClassMetadataReader { private final SimpleClassMetadata simpleClassMetadata; - public static SimpleClassMetadata readSimpleClassMetadata(byte[] classBinary) { - SimpleClassMetadataReader simpleClassMetadataReader = new SimpleClassMetadataReader(classBinary); + public static SimpleClassMetadata readSimpleClassMetadata(final byte[] classBinary) { + final SimpleClassMetadataReader simpleClassMetadataReader = new SimpleClassMetadataReader(new ClassReaderWrapper(classBinary)); return simpleClassMetadataReader.getSimpleClassMetadata(); } - SimpleClassMetadataReader(byte[] classBinary) { - if (classBinary == null) { - throw new NullPointerException("classBinary must not be null"); - } - - final ClassReader classReader = new ClassReader(classBinary); - - int accessFlag = classReader.getAccess(); - String className = classReader.getClassName(); - String superClassName = classReader.getSuperName(); - String[] interfaceNameList = classReader.getInterfaces(); - -// int offset = 0; -// int version = classReader.readShort(offset + 6); -// offset is zero - int version = classReader.readShort(6); - - this.simpleClassMetadata = new DefaultSimpleClassMetadata(version, accessFlag, className, superClassName, interfaceNameList, classBinary); + SimpleClassMetadataReader(final ClassReaderWrapper classReader) { + this.simpleClassMetadata = new DefaultSimpleClassMetadata(classReader.getVersion(), classReader.getAccess(), classReader.getClassInternalName(), classReader.getSuperClassInternalName(), classReader.getInterfaceInternalNames(), classReader.getClassBinary()); } public SimpleClassMetadata getSimpleClassMetadata() { return simpleClassMetadata; } - - -} +} \ No newline at end of file diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JarReader.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JarReader.java index 750c6b077..27b305d8a 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JarReader.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JarReader.java @@ -49,6 +49,15 @@ public class JarReader { this.jarFile = jarFile; } + public InputStream getInputStream(String name) throws IOException { + final JarEntry jarEntry = this.jarFile.getJarEntry(name); + if (jarEntry != null) { + return this.jarFile.getInputStream(jarEntry); + } + + return null; + } + public List read(JarEntryFilter jarEntryFilter) throws IOException{ if (jarEntryFilter == null) { throw new NullPointerException("jarEntryFilter must not be null"); @@ -125,6 +134,4 @@ public class JarReader { } } } - - } diff --git a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtils.java b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtils.java index d5b6cc378..6527d22a8 100644 --- a/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtils.java +++ b/profiler/src/main/java/com/navercorp/pinpoint/profiler/util/JavaAssistUtils.java @@ -183,11 +183,12 @@ public final class JavaAssistUtils { * @param jvmNameArray * @return */ - public static List jvmNameToJavaName(String[] jvmNameArray) { + public static List jvmNameToJavaName(List jvmNameArray) { if (jvmNameArray == null) { return Collections.emptyList(); } - List list = new ArrayList(jvmNameArray.length); + + List list = new ArrayList(jvmNameArray.size()); for (String jvmName : jvmNameArray) { list.add(jvmNameToJavaName(jvmName)); } diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/AnnotationMetadataVisitorTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/AnnotationMetadataVisitorTest.java new file mode 100644 index 000000000..e763bdf03 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/AnnotationMetadataVisitorTest.java @@ -0,0 +1,109 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.junit.Test; +import org.objectweb.asm.ClassReader; + +import java.io.InputStream; +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author jaehong.kim + */ +public class AnnotationMetadataVisitorTest { + + @Test + public void visitAnnotation() throws Exception { + final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream in = classLoader.getResourceAsStream(JavaAssistUtils.javaNameToJvmName(HasAnnotation.class.getName()) + ".class"); + + AnnotationMetadataVisitor visitor = new AnnotationMetadataVisitor(); + ClassReader reader = new ClassReader(in); + in.close(); + reader.accept(visitor, 0); + + assertTrue(visitor.getAnnotationInternalNames().contains(JavaAssistUtils.javaNameToJvmName(SimpleClassAnnotation.class.getName()))); + assertTrue(visitor.getAnnotationInternalNames().contains(JavaAssistUtils.javaNameToJvmName(RetentionPolicyClassAnnotation.class.getName()))); + assertTrue(visitor.getAnnotationInternalNames().contains(JavaAssistUtils.javaNameToJvmName(RetentionPolicyRuntimeAnnotation.class.getName()))); + // skip source + assertFalse(visitor.getAnnotationInternalNames().contains(JavaAssistUtils.javaNameToJvmName(RetentionPolicySourceAnnotation.class.getName()))); + } + + + @Test + public void visitMetaAnnotation() throws Exception { + final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + InputStream in = classLoader.getResourceAsStream(JavaAssistUtils.javaNameToJvmName(HasMetaAnnotation.class.getName()) + ".class"); + + AnnotationMetadataVisitor visitor = new AnnotationMetadataVisitor(); + ClassReader reader = new ClassReader(in); + in.close(); + reader.accept(visitor, 0); + + assertTrue(visitor.getAnnotationInternalNames().contains(JavaAssistUtils.javaNameToJvmName(NestedMetaAnnotation.class.getName()))); + // no consider hierarchy. + assertFalse(visitor.getAnnotationInternalNames().contains(JavaAssistUtils.javaNameToJvmName(RetentionPolicyClassAnnotation.class.getName()))); + } + + + @Documented + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.CLASS) + @interface SimpleClassAnnotation { + } + + @Documented + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.CLASS) + @interface RetentionPolicyClassAnnotation { + } + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @interface RetentionPolicyRuntimeAnnotation { + } + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.SOURCE) + @interface RetentionPolicySourceAnnotation { + } + + @RetentionPolicyClassAnnotation + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.CLASS) + @interface NestedMetaAnnotation { + } + + @SimpleClassAnnotation + @RetentionPolicyClassAnnotation + @RetentionPolicyRuntimeAnnotation + @RetentionPolicySourceAnnotation + class HasAnnotation { + } + + @NestedMetaAnnotation + class HasMetaAnnotation { + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapperTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapperTest.java new file mode 100644 index 000000000..a60123f88 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/ClassReaderWrapperTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import com.navercorp.pinpoint.common.util.ClassLoaderUtils; +import com.navercorp.pinpoint.profiler.util.BytecodeUtils; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.junit.Test; + +import javax.annotation.Resource; +import java.io.ByteArrayInputStream; +import java.lang.annotation.Target; + +import static org.junit.Assert.*; + +/** + * @author jaehong.kim + */ +public class ClassReaderWrapperTest { + + @Test + public void base() throws Exception { + final Class clazz = String.class; + final byte[] classBinary = BytecodeUtils.getClassFile(ClassLoaderUtils.getDefaultClassLoader(), clazz.getName()); + + assertClassReader(new ClassReaderWrapper(classBinary)); + assertClassReader(new ClassReaderWrapper(ClassLoaderUtils.getDefaultClassLoader(), JavaAssistUtils.javaNameToJvmName(clazz.getName()))); + } + + @Test + public void annotation() throws Exception { + ClassReaderWrapper classReader = new ClassReaderWrapper(ClassLoaderUtils.getDefaultClassLoader(), JavaAssistUtils.javaNameToJvmName(AnnotationMock.class.getName())); + classReader.getAnnotationInternalNames().contains("java/lang/Deprecated"); + classReader.getAnnotationInternalNames().contains("javax/annotation/Resource"); + } + + private void assertClassReader(ClassReaderWrapper classReader) { + assertEquals("java/lang/String", classReader.getClassInternalName()); + assertEquals("java/lang/Object", classReader.getSuperClassInternalName()); + System.out.println(classReader.getInterfaceInternalNames()); + assertTrue(classReader.getInterfaceInternalNames().contains("java/lang/Comparable")); + assertTrue(classReader.getInterfaceInternalNames().contains("java/io/Serializable")); + classReader.getVersion(); + classReader.getAccess(); + assertNotNull(classReader.getClassBinary()); + } + + + @Deprecated + @Resource + class AnnotationMock { + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadataTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadataTest.java new file mode 100644 index 000000000..45c583091 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultInternalClassMetadataTest.java @@ -0,0 +1,55 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; + +import static org.junit.Assert.*; + +/** + * @author jaehong.kim + */ +public class DefaultInternalClassMetadataTest { + + @Test + public void base() throws Exception { + DefaultInternalClassMetadata classMetadata = new DefaultInternalClassMetadata("java/lang/String", "java/lang/Object", Arrays.asList("java/lang/Comparable", "java/lang/Serializable"), Collections.EMPTY_LIST); + // name + assertEquals("java/lang/String", classMetadata.getClassInternalName()); + // super + assertEquals("java/lang/Object", classMetadata.getSuperClassInternalName()); + // interfaces + assertTrue(classMetadata.getInterfaceInternalNames().contains("java/lang/Comparable")); + assertTrue(classMetadata.getInterfaceInternalNames().contains("java/lang/Serializable")); + // annotation + assertEquals(0, classMetadata.getAnnotationInternalNames().size()); + } + + @Test + public void interfaceNamesNull() throws Exception { + DefaultInternalClassMetadata classMetadata = new DefaultInternalClassMetadata("java/lang/String", "java/lang/Object", null, Collections.EMPTY_LIST); + assertEquals(0, classMetadata.getInterfaceInternalNames().size()); + } + + @Test + public void annotationNamesNull() throws Exception { + DefaultInternalClassMetadata classMetadata = new DefaultInternalClassMetadata("java/lang/String", "java/lang/Object", Arrays.asList("java/lang/Comparable", "java/lang/Serializable"), null); + assertEquals(0, classMetadata.getAnnotationInternalNames().size()); + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadataTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadataTest.java new file mode 100644 index 000000000..c2774cb38 --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/DefaultSimpleClassMetadataTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.*; + +/** + * @author jaehong.kim + */ +public class DefaultSimpleClassMetadataTest { + + @Test + public void base() throws Exception { + final byte[] classBinary = new byte[1]; + DefaultSimpleClassMetadata classMetadata = new DefaultSimpleClassMetadata(1, 1, "java/lang/String", "java/lang/Object", Arrays.asList("java/lang/Comparable", "java/lang/Serializable"), classBinary); + assertEquals("java.lang.String", classMetadata.getClassName()); + assertEquals("java.lang.Object", classMetadata.getSuperClassName()); + assertTrue(classMetadata.getInterfaceNames().contains("java.lang.Comparable")); + assertTrue(classMetadata.getInterfaceNames().contains("java.lang.Serializable")); + assertEquals(1, classMetadata.getAccessFlag()); + assertEquals(1, classMetadata.getVersion()); + assertEquals(classBinary, classMetadata.getClassBinary()); + } + + @Test + public void interfaceNameNull() throws Exception { + final byte[] classBinary = new byte[1]; + DefaultSimpleClassMetadata classMetadata = new DefaultSimpleClassMetadata(1, 1, "java/lang/String", "java/lang/Object", null, classBinary); + assertEquals(0, classMetadata.getInterfaceNames().size()); + } +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReaderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReaderTest.java new file mode 100644 index 000000000..6e90826ca --- /dev/null +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/InternalClassMetadataReaderTest.java @@ -0,0 +1,71 @@ +/* + * Copyright 2017 NAVER Corp. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.navercorp.pinpoint.profiler.instrument.classreading; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import com.navercorp.pinpoint.common.util.ClassLoaderUtils; +import com.navercorp.pinpoint.profiler.util.BytecodeUtils; +import com.navercorp.pinpoint.profiler.util.JavaAssistUtils; +import org.junit.Test; + +import java.lang.annotation.Annotation; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * @author jaehong.kim + */ +public class InternalClassMetadataReaderTest { + + @Test + public void getInternalClassMetadata() throws Exception { + final Class clazz = String.class; + final byte[] classBinary = BytecodeUtils.getClassFile(ClassLoaderUtils.getDefaultClassLoader(), clazz.getName()); + + InternalClassMetadata classMetadata = InternalClassMetadataReader.readInternalClassMetadata(classBinary); + // name + assertEquals(JavaAssistUtils.javaNameToJvmName(clazz.getName()), classMetadata.getClassInternalName()); + + // interfaces + for(Class interfacez : clazz.getInterfaces()) { + final String interfaceInternalName = JavaAssistUtils.javaNameToJvmName(interfacez.getName()); + classMetadata.getInterfaceInternalNames().contains(interfaceInternalName); + } + + // super + assertEquals("java/lang/Object", classMetadata.getSuperClassInternalName()); + + // annotations + for (Annotation annotation : clazz.getAnnotations()) { + final String annotationInternalName = JavaAssistUtils.javaNameToJvmName(annotation.annotationType().getName()); + classMetadata.getAnnotationInternalNames().contains(annotationInternalName); + } + } + + @Test + public void SuperIsNull() throws Exception { + final Class clazz = Object.class; + final byte[] classBinary = BytecodeUtils.getClassFile(ClassLoaderUtils.getDefaultClassLoader(), clazz.getName()); + InternalClassMetadata classMetadata = InternalClassMetadataReader.readInternalClassMetadata(classBinary); + // name + assertEquals(JavaAssistUtils.javaNameToJvmName(clazz.getName()), classMetadata.getClassInternalName()); + // super + assertNull(classMetadata.getSuperClassInternalName()); + } + +} \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadataReaderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadataReaderTest.java index 46c78599a..911411cd0 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadataReaderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/instrument/classreading/SimpleClassMetadataReaderTest.java @@ -42,19 +42,24 @@ public class SimpleClassMetadataReaderTest { byte[] classFile = BytecodeUtils.getClassFile(ClassLoaderUtils.getDefaultClassLoader(), clazz.getName()); SimpleClassMetadata simpleClassMetadata = SimpleClassMetadataReader.readSimpleClassMetadata(classFile); - + // name. Assert.assertEquals(simpleClassMetadata.getClassName(), clazz.getName()); - + // interfaces List interfaceList = getInterfaceList(clazz.getInterfaces()); List interfaceNames = simpleClassMetadata.getInterfaceNames(); Assert.assertThat(interfaceNames, containsInAnyOrder(interfaceList.toArray())); + // super Assert.assertEquals(simpleClassMetadata.getSuperClassName(), "java.lang.Object"); + + // access + simpleClassMetadata.getAccessFlag(); + // version + simpleClassMetadata.getVersion(); } private List getInterfaceList(Class[] interfaces) { - List> collection = Lists.newArrayList(interfaces); return Lists.transform(collection, new Function, String>() { @Override @@ -63,5 +68,4 @@ public class SimpleClassMetadataReaderTest { } }); } - } \ No newline at end of file diff --git a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JarReaderTest.java b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JarReaderTest.java index 05cff0a36..68d1d5be3 100644 --- a/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JarReaderTest.java +++ b/profiler/src/test/java/com/navercorp/pinpoint/profiler/util/JarReaderTest.java @@ -23,6 +23,7 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.InputStream; import java.net.URL; import java.util.List; import java.util.jar.JarFile; @@ -48,4 +49,13 @@ public class JarReaderTest { Assert.assertThat(fileBinary.getFileName(), Matchers.endsWith(".class")); } } + + @Test + public void getInputStream() throws Exception { + URL location = Logger.class.getProtectionDomain().getCodeSource().getLocation(); + JarFile jarFile = new JarFile(location.getPath()); + JarReader jarReader = new JarReader(jarFile); + Assert.assertNotNull(jarReader.getInputStream("org/slf4j/Logger.class")); + Assert.assertNull(jarReader.getInputStream("org/slf4j/NotFound.class")); + } } \ No newline at end of file