de.spricom.dessert.partitioning.AnnotationMatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dessert-core Show documentation
Show all versions of dessert-core Show documentation
A library for unit-tests to check the dependencies between classes.
The newest version!
package de.spricom.dessert.partitioning;
/*-
* #%L
* Dessert Dependency Assertion Library for Java
* %%
* Copyright (C) 2017 - 2023 Hans Jörg Heßmann
* %%
* 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.
* #L%
*/
import de.spricom.dessert.classfile.ClassFile;
import de.spricom.dessert.classfile.FieldInfo;
import de.spricom.dessert.classfile.MethodInfo;
import de.spricom.dessert.classfile.attribute.*;
import de.spricom.dessert.util.AnnotationPattern;
import de.spricom.dessert.util.Predicate;
import java.util.BitSet;
import java.util.Map;
class AnnotationMatcher implements Predicate {
private final AnnotationPattern pattern;
AnnotationMatcher(AnnotationPattern pattern) {
this.pattern = pattern;
}
@Override
public boolean test(ClassFile classFile) {
if (matchesAny(classFile.getAttributes())) {
return true;
}
for (FieldInfo field : classFile.getFields()) {
if (matchesAny(field.getAttributes())) {
return true;
}
}
for (MethodInfo method : classFile.getMethods()) {
if (matchesAny(method.getAttributes())) {
return true;
}
// Code attributes may have RuntimeVisibleTypeAnnotations or RuntimeInvisibleTypeAnnotations.
for (CodeAttribute code : Attributes.filter(classFile.getAttributes(), CodeAttribute.class)) {
if (matchesAny(code.getAttributes())) {
return true;
}
}
}
for (RecordAttribute record : Attributes.filter(classFile.getAttributes(), RecordAttribute.class)) {
for (RecordAttribute.RecordComponentInfo component : record.getComponents()) {
if (matchesAny(component.getAttributes())) {
return true;
}
}
}
return false;
}
private boolean matchesAny(AttributeInfo[] attributes) {
for (AttributeInfo attribute : attributes) {
if (attribute instanceof AbstractAnnotationsAttribute) {
AbstractAnnotationsAttribute annotationsAttribute =
(AbstractAnnotationsAttribute) attribute;
if (matchesAny(annotationsAttribute.getAnnotations())) {
return true;
}
} else if (attribute instanceof AbstractParameterAnnotationsAttribute) {
AbstractParameterAnnotationsAttribute annotationsAttribute =
(AbstractParameterAnnotationsAttribute) attribute;
for (ParameterAnnotation parameterAnnotation : annotationsAttribute.getParameterAnnotations()) {
if (matchesAny(parameterAnnotation.getAnnotations())) {
return true;
}
}
} else if (attribute instanceof AbstractTypeAnnotationsAttribute) {
AbstractTypeAnnotationsAttribute annotationsAttribute =
(AbstractTypeAnnotationsAttribute) attribute;
if (matchesAny(annotationsAttribute.getTypeAnnotations())) {
return true;
}
}
}
return false;
}
private boolean matchesAny(TypeAnnotation[] typeAnnotations) {
for (TypeAnnotation typeAnnotation : typeAnnotations) {
if (matches(typeAnnotation.getAnnotation())) {
return true;
}
}
return false;
}
private boolean matchesAny(Annotation[] annotations) {
for (Annotation annotation : annotations) {
if (matches(annotation)) {
return true;
}
}
return false;
}
private boolean matches(Annotation annotation) {
if (!annotation.getType().getObjectTypeClassname().equals(pattern.getAnnotationClassName())) {
return false;
}
for (Map.Entry member : pattern.getAnnotationMembers().entrySet()) {
if (!hasMember(annotation, member.getKey(), member.getValue())) {
return false;
}
}
return true;
}
private boolean hasMember(Annotation annotation, String key, Object value) {
for (ElementValuePair elementValuePair : annotation.getElementValuePairs()) {
if (key.equals(elementValuePair.getName())) {
return matches(elementValuePair.getValue(), value);
}
}
return false;
}
private boolean matches(ElementValue value, Object patternValue) {
switch (value.getTag()) {
case 'B':
case 'C':
case 'D':
case 'F':
case 'I':
case 'J':
case 'S':
case 's':
return patternValue.equals(value.getConstantValue().getValue());
case 'Z':
return patternValue.equals(Integer.valueOf(1).equals(value.getConstantValue().getValue()));
case 'e':
return patternValue.getClass().getName().equals(value.getType().getDeclaration())
&& patternValue.toString().equals(value.getConstantValue().getValue());
case 'c':
return ((Class>) patternValue).getName().equals(value.getType().getDeclaration());
case '@':
return new AnnotationMatcher((AnnotationPattern) patternValue).matches(value.getAnnotation());
case '[':
return matches(value.getValues(), patternValue);
default:
throw new IllegalArgumentException("Invalid ElementValue tag: " + value.getTag());
}
}
private boolean matches(ElementValue[] values, Object patternValue) {
Object[] patternValues = patternValue instanceof Object[]
? (Object[]) patternValue
: new Object[]{patternValue};
if (values.length != patternValues.length) {
return false;
}
BitSet matches = new BitSet((patternValues).length);
for (ElementValue value : values) {
for (int i = matches.nextClearBit(0);
i < patternValues.length; i = matches.nextClearBit(i + 1)) {
if (matches(value, patternValues[i])) {
matches.set(i);
break;
}
}
}
return matches.cardinality() == patternValues.length;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy