use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.
the class ClassMatch method processRequiredClassAnnotations.
private void processRequiredClassAnnotations(ClassCache cache) {
final List<AnnotationNode> annotationsInOriginal = WeaveUtils.getClassAnnotations(original);
Set<String> classAnnotations = Sets.newHashSetWithExpectedSize(annotationsInOriginal.size());
for (AnnotationNode annotationNode : annotationsInOriginal) {
classAnnotations.add(Type.getType(annotationNode.desc).getClassName());
}
// Exact match
if (isOneOfRequiredAnnotations(classAnnotations, requiredClassAnnotations)) {
return;
}
if (WeaveUtils.isWeaveWithAnnotationInterfaceMatch(weave)) {
try {
for (String interfaceName : original.interfaces) {
ClassInformation interfaceInformation = cache.getClassInformation(interfaceName);
if (isOneOfRequiredAnnotations(interfaceInformation.classAnnotationNames, requiredClassAnnotations)) {
return;
}
}
} catch (IOException e) {
}
}
addViolation(CLASS_MISSING_REQUIRED_ANNOTATIONS);
}
use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.
the class ClassMatch method match.
private void match(ClassCache cache) {
// cannot annotate an interface
if ((weave.access & Opcodes.ACC_INTERFACE) != 0) {
addViolation(CLASS_WEAVE_IS_INTERFACE);
fatalWeaveViolation = true;
return;
}
if ((weave.access & Opcodes.ACC_ENUM) != 0) {
processEnumMethods();
}
if (weave.version > WeaveUtils.RUNTIME_MAX_SUPPORTED_CLASS_VERSION) {
addViolation(INCOMPATIBLE_BYTECODE_VERSION);
}
boolean isWeaveWithAnnotation = !requiredClassAnnotations.isEmpty() || !requiredMethodAnnotations.isEmpty();
// cannot increase class visibility
if ((original.access & Opcodes.ACC_PUBLIC) != (weave.access & Opcodes.ACC_PUBLIC)) {
// WeaveWithAnnotation class access does not need to match original class access
if (!isWeaveWithAnnotation) {
addViolation(CLASS_ACCESS_MISMATCH);
}
}
// weave can only implement interfaces that the original implements
if (weave.interfaces.size() > 0) {
for (String weaveInterface : weave.interfaces) {
if (!allOriginalInterfaces.contains(weaveInterface)) {
addViolation(CLASS_IMPLEMENTS_ILLEGAL_INTERFACE);
}
}
}
if (!requiredClassAnnotations.isEmpty()) {
processRequiredClassAnnotations(cache);
}
if (requiredClassAnnotations.isEmpty() && !requiredMethodAnnotations.isEmpty()) {
processRequiredMethodAnnotations(cache);
}
// weave can only extend the exact superclass that the original extends
if (!weave.superName.equals(WeaveUtils.JAVA_LANG_OBJECT_NAME) && !weave.superName.equals(original.superName)) {
addViolation(CLASS_EXTENDS_ILLEGAL_SUPERCLASS);
}
// weave cannot be a non-static inner class
if (WeaveUtils.isNonstaticInnerClass(weave)) {
addViolation(CLASS_NESTED_NONSTATIC_UNSUPPORTED);
}
weavesAllMethod = findAndValidateWeaveIntoAllMethod();
// identify new, anonymous, and matched inner classes
Map<String, InnerClassNode> originalInnerClasses = new HashMap<>();
for (InnerClassNode innerClassNode : original.innerClasses) {
originalInnerClasses.put(innerClassNode.name, innerClassNode);
}
for (InnerClassNode weaveInnerClass : weave.innerClasses) {
String name = weaveInnerClass.name;
if (weave.name.equals(name)) {
// if the weave class IS an inner class, it will be listed - skip it
continue;
}
if (weaveInnerClass.outerName != null && !weaveInnerClass.outerName.equals(weave.name)) {
// we're using an inner class from another class - skip it
continue;
}
if (WeaveUtils.isAnonymousInnerClass(weaveInnerClass)) {
// all anon classes are new
newInnerClasses.add(name);
} else if (originalInnerClasses.containsKey(name)) {
matchedInnerClasses.add(name);
} else {
newInnerClasses.add(name);
}
}
// identify new and matched fields
Map<String, FieldNode> originalFields = new HashMap<>();
for (FieldNode originalField : original.fields) {
originalFields.put(originalField.name, originalField);
}
for (FieldNode weaveField : weave.fields) {
if (weaveField.name.equals(SERIAL_VERSION_UID_FIELD_NAME)) {
addViolation(FIELD_SERIALVERSIONUID_UNSUPPORTED, weaveField);
continue;
}
FieldNode originalField = originalFields.get(weaveField.name);
if (originalField == null) {
newFields.add(weaveField.name);
} else {
validateMatchedField(originalField, weaveField);
matchedFields.add(weaveField.name);
}
}
if ((weave.access & Opcodes.ACC_ENUM) != 0) {
if (newFields.size() > 0) {
addViolation(ENUM_NEW_FIELD);
}
}
// identify new and matched methods
MethodNode clinit = null;
for (MethodNode weaveMethod : weave.methods) {
if (weaveMethod.name.equals(WeaveUtils.CLASS_INIT_NAME)) {
clinit = weaveMethod;
// we don't weave <clinit> into a target (only extensions)
continue;
}
if (weaveMethod.name.equals(WeaveUtils.INIT_NAME)) {
// validate ctor field assignment calls and remove redundant Weaver.callOriginal() invocations
// must happen before we skip empty ctors below to support final field assignments w/out a ctor match
// see ConstructorWeaveTest.testInitFinalFieldWithNoDefaultConstructor()
processInitFieldAssignment(weaveMethod);
}
if (WeaveUtils.isEmptyConstructor(weaveMethod)) {
// skip empty constructors
continue;
}
if ((weaveMethod.access & Opcodes.ACC_BRIDGE) != 0) {
// skip autogenerated bridge methods
continue;
}
if (WeaveUtils.isSyntheticAccessor(weaveMethod.name)) {
if ((weaveMethod.access & Opcodes.ACC_SYNTHETIC) != Opcodes.ACC_SYNTHETIC) {
addViolation(METHOD_SYNTHETIC_WEAVE_ILLEGAL, weaveMethod);
continue;
}
GeneratedNewFieldMethod generatedNewFieldMethod = GeneratedNewFieldMethod.isGeneratedNewFieldMethod(weaveMethod, newFields);
if (generatedNewFieldMethod != null) {
generatedNewFieldMethods.put(generatedNewFieldMethod.method, generatedNewFieldMethod);
}
// generated methods are handled specially
continue;
}
if (WeaveUtils.hasWeaveIntoAllMethodsAnnotation(weaveMethod)) {
processWeaveIntoAllMethods(weaveMethod, cache);
continue;
}
MatchableMethod matchedMethod = matchableMethods.get(new MethodKey(weaveMethod));
Method asmMethod = new Method(weaveMethod.name, weaveMethod.desc);
if (matchedMethod == null) {
newMethods.add(asmMethod);
} else {
validateMatchedMethod(matchedMethod, weaveMethod);
matchedMethods.add(asmMethod);
}
}
if (null != clinit) {
// clinit matching needs to go last, which is why we didn't do it in the loop
extensionClassInit = validateClassInit(clinit);
}
// we do not call validateMatchedMethod because there is no original
if (isInterfaceMatch && newMethods.contains(WeaveUtils.DEFAULT_CONSTRUCTOR)) {
newMethods.remove(WeaveUtils.DEFAULT_CONSTRUCTOR);
matchedMethods.add(WeaveUtils.DEFAULT_CONSTRUCTOR);
}
weavesAllConstructors = validateWeaveAllConstructors();
boolean collectClassAnnotations = false;
// validate weave methods *after* match - match info is needed, e.g. to ensure no new methods call each other
for (MethodNode weaveMethod : weave.methods) {
WeaveMethodInstructionScanner instructionInfo = new WeaveMethodInstructionScanner();
weaveMethod.accept(instructionInfo);
validateWeaveMethod(weaveMethod, instructionInfo);
if (instructionInfo.isClassAnnotationGetter) {
classAnnotationGetters.add(weaveMethod);
collectClassAnnotations = true;
}
if (instructionInfo.isMethodAnnotationGetter) {
if (weaveMethod.equals(weavesAllMethod)) {
for (MethodNode originalMethod : original.methods) {
storeMethodAnnotations(originalMethod);
}
} else {
MethodNode originalMethod = WeaveUtils.getMethodNode(original, weaveMethod.name, weaveMethod.desc);
storeMethodAnnotations(originalMethod);
}
if (WeaveUtils.isWeaveWithAnnotationInterfaceMatch(weave)) {
// Add store method annotations for methods in interface
for (String interfaceName : original.interfaces) {
try {
ClassInformation interfaceInformation = cache.getClassInformation(interfaceName);
Set<MethodKey> weaveMethodKeys = new HashSet<>();
for (MethodNode method : weave.methods) {
weaveMethodKeys.add(new MethodKey(method));
}
for (MethodNode method : weaveAllMatchedMethods.keySet()) {
weaveMethodKeys.add(new MethodKey(method));
}
for (ClassInformation.MemberInformation method : interfaceInformation.methods) {
// If method is same as weave method,
// Pull out method annotations and add it to methodToAnnotations
MethodKey methodKey = new MethodKey(method.name, method.desc);
if (weaveMethodKeys.contains(methodKey)) {
if (!methodsToAnnotations.containsKey(methodKey)) {
methodsToAnnotations.put(methodKey, new HashMap<String, AnnotationNode>());
}
for (AnnotationNode annotation : method.annotations) {
methodsToAnnotations.get(methodKey).put(Type.getType(annotation.desc).getClassName(), annotation);
}
}
}
} catch (IOException ignored) {
}
// Need to get annotation nodes for each member in interfaceInformation.
}
}
}
}
if (collectClassAnnotations) {
List<AnnotationNode> classAnnotations = WeaveUtils.getClassAnnotations(original);
for (AnnotationNode classAnnotation : classAnnotations) {
classAnnotationMap.put(Type.getType(classAnnotation.desc).getClassName(), classAnnotation);
}
if (WeaveUtils.isWeaveWithAnnotationInterfaceMatch(weave)) {
// Collect interface annotations.
for (String interfaceName : original.interfaces) {
try {
ClassInformation interfaceInformation = cache.getClassInformation(interfaceName);
for (AnnotationNode annotationNode : interfaceInformation.classAnnotationNodes) {
classAnnotationMap.put(Type.getType(annotationNode.desc).getClassName(), annotationNode);
}
} catch (IOException ignored) {
}
}
}
}
}
use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.
the class PublicNewFieldTest method weaveClass.
private static void weaveClass(String origName, PackageValidationResult result, ClassCache cache) throws IOException {
ClassInformation ci = cache.getClassInformation(origName);
byte[] compositeBytes = result.weave(WeaveUtils.getClassInternalName(origName), ci.getAllSuperNames(cache).toArray(new String[0]), ci.getAllInterfaces(cache).toArray(new String[0]), WeaveTestUtils.getClassBytes(origName), cache, Collections.emptyMap()).getCompositeBytes(cache);
Assert.assertNotNull("Unable to weave: " + origName, compositeBytes);
Assert.assertFalse("Original class should not be already loaded: " + origName, ClassLoaderUtils.isClassLoadedOnClassLoader(CLASSLOADER, WeaveUtils.getClassBinaryName(origName)));
WeaveTestUtils.addToContextClassloader(origName, compositeBytes);
}
use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.
the class WeavePackageManagerTest method testBootstrapWeave.
@Test
public void testBootstrapWeave() throws IOException {
List<byte[]> weaveBytes = new ArrayList<>();
weaveBytes.add(WeaveTestUtils.getClassBytes("com.newrelic.weave.weavepackage.WeavePackageManagerTest$ResultSet"));
WeavePackageConfig config = WeavePackageConfig.builder().name("weave_bootstrap").source("com.newrelic.weave.weavepackage.WeavePackageManagerTest").build();
WeavePackage bsPackage = new WeavePackage(config, weaveBytes);
Assert.assertTrue(bsPackage.weavesBootstrap());
WeaveTestUtils.expectViolations(bsPackage.validate(new ClassCache(BootstrapLoader.get())));
WeavePackageManager wpm = new WeavePackageManager(null, Mockito.mock(Instrumentation.class), 10, true, true);
Assert.assertTrue(wpm.canWeaveBootstrapClassLoader());
wpm.register(bsPackage);
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
ClassCache cache = new ClassCache(new ClassLoaderFinder(classloader));
String targetClassName = "com.newrelic.weave.weavepackage.WeavePackageManagerTest$ResultSetImpl";
String targetInternalName = targetClassName.replace('.', '/');
ClassInformation classInformation = cache.getClassInformation(targetInternalName);
Assert.assertNotNull(classInformation);
String[] superNames = classInformation.getAllSuperNames(cache).toArray(new String[0]);
String[] interfaceNames = classInformation.getAllInterfaces(cache).toArray(new String[0]);
Assert.assertEquals(1, wpm.match(classloader, targetInternalName, cache).size());
byte[] result = wpm.weave(classloader, targetInternalName, WeaveTestUtils.getClassBytes(targetClassName), Collections.emptyMap());
Assert.assertTrue(bsPackage.hasMatcher(targetInternalName, superNames, interfaceNames, Collections.<String>emptySet(), Collections.<String>emptySet(), null));
Assert.assertEquals(0, getCacheSize(wpm.invalidPackages));
Assert.assertEquals(1, getCacheSize(wpm.validPackages));
Assert.assertNotNull(wpm.validPackages.getIfPresent(BootstrapLoader.PLACEHOLDER));
Assert.assertNotNull(wpm.validPackages.getIfPresent(BootstrapLoader.PLACEHOLDER).get(bsPackage));
Assert.assertNotNull(result);
}
use of com.newrelic.weave.utils.ClassInformation in project newrelic-java-agent by newrelic.
the class WeavePackageManager method match.
/**
* Determine if the specified class and class loader match any packages.
*
* @param classloader classloader containing classpath to validate against
* @param className name of the class
* @param cache {@link ClassCache} used to resolve classes without loading them
* @return validation result set
*/
public Set<PackageValidationResult> match(ClassLoader classloader, String className, ClassCache cache) throws IOException {
classloader = classLoaderSub(classloader);
ClassInformation classInformation = cache.getClassInformation(className);
if (null == classInformation) {
return Collections.emptySet();
}
String[] superNames = classInformation.getAllSuperNames(cache).toArray(new String[0]);
String[] interfaceNames = classInformation.getAllInterfaces(cache).toArray(new String[0]);
Set<String> classAnnotations = classInformation.classAnnotationNames;
Set<String> methodAnnotations = classInformation.methodAnnotationNames;
return match(classloader, cache, className, classAnnotations, methodAnnotations, superNames, interfaceNames);
}
Aggregations