
org.opalj.av.checking.AnnotationPredicate.scala Maven / Gradle / Ivy
The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package av
package checking
import org.opalj.br._
import org.opalj.br.ConcreteSourceElement
/**
* Matches an annotation of a class, field, method or method parameter.
*
* @author Marco Torsello
*/
trait AnnotationPredicate extends SourceElementPredicate[ConcreteSourceElement] {
def apply(other: Annotation): Boolean
def toDescription(): String
}
/**
* An annotation matcher that always returns `true`; it matches any annotation.
*
* @author Marco Torsello
*/
case object AnyAnnotation extends AnnotationPredicate {
override def apply(other: Annotation): Boolean = true
override def apply(other: ConcreteSourceElement): Boolean = true
override def toDescription(): String = "/*any annotation*/";
}
/**
* Matches an annotation of a class, field, method or method parameter that has the
* specified type. The annotation is matched independent of the annotation's values.
*
* ==Example==
* {{{
* scala> import org.opalj.br._
* scala> val foo = ObjectType("java/lang/Foo")
* scala> val aw = org.opalj.av.checking.AnnotatedWith(foo)
* aw: org.opalj.av.checking.AnnotatedWith = @java.lang.Foo
* scala> aw(Annotation(foo,IndexedSeq(ElementValuePair("clazz",StringValue(" ")))))
* res: Boolean = true
* }}}
* @author Marco Torsello
*/
case class HasAnnotation(annotationType: FieldType) extends AnnotationPredicate {
/**
* Checks if the type of the given annotation is the same as the type of this
* predicate.
*/
def apply(other: Annotation): Boolean = other.annotationType eq this.annotationType
override def apply(sourceElement: ConcreteSourceElement): Boolean = {
sourceElement.annotations.exists(this(_))
}
override def toDescription(): String = "@"+annotationType.toJava
}
/**
* Factory methods to create [[AnnotatedWith]] predicates.
*/
object HasAnnotation {
def apply(annotationType: String): HasAnnotation = {
new HasAnnotation(ObjectType(annotationType.replace('.', '/')))
}
}
/**
* Tests if an annotation of a class, field, method or method parameter is as specified.
* The test takes the element values into consideration; if you don't want to take
* them into consideration use a [[HasAnnotation]] predicate.
*
* {{{
* scala> import org.opalj.br._
* scala> import org.opalj.av.checking._
* scala> val foo = ObjectType("java/lang/Foo")
*
* scala> val am = AnnotationPredicate("java.lang.Foo",Map("clazz" -> StringValue("")))
* am: org.opalj.av.checking.AnnotationPredicate = @java.lang.Foo(clazz="")
*
* scala> am(Annotation(foo,IndexedSeq(ElementValuePair("clazz",StringValue("")))))
* res: Boolean = true
*
* scala> am(Annotation(foo,IndexedSeq(ElementValuePair("clazz",StringValue("-+-")))))
* res: Boolean = false
*
* scala> val am = DefaultAnnotationPredicate("java.lang.Foo",IndexedSeq.empty)
* am: org.opalj.av.checking.DefaultAnnotationPredicate = @java.lang.Foo()
*
* scala> am(Annotation(ObjectType("java/lang/Foo"),IndexedSeq(ElementValuePair("clazz",StringValue(" ")))))
* res: Boolean = false
* }}}
*
* @author Marco Torsello
*/
case class AnnotatedWith(
annotationType: FieldType,
elementValuePairs: Seq[ElementValuePair]
)
extends AnnotationPredicate {
/**
* Checks if the given annotation is as specified by this predicate.
* Returns `true` if the given annotation has the type `annotationType`and
* if all element value pairs are matched independent of their order.
*
* ==Example Scenarios==
* - If the predicate's annotation type is `A` and the other annotation's type is `B`
* then the elements will not match.
*
* - If the predicate defines specific [[org.opalj.br.ElementValuePair]]s such as
* `ArrayBuffer(ElementValuePair("target", ClassValue("org.opalj.av.checking.AnnotationPredicate")),
* ElementValuePair("name", StringValue("Annotation_Predicate"))`
* it will then match annotations where the [[org.opalj.br.ElementValuePair]]s have a different order:
* `ArrayBuffer(ElementValuePair("name", StringValue("Annotation_Predicate"),
* ElementValuePair("target", ClassValue("org.opalj.av.checking.AnnotationPredicate")))`
* But it will not match if one or both of the two [[org.opalj.br.ElementValuePair]]s are missing or there is
* another [[org.opalj.br.ElementValuePair]] not defined by this predicate.
*/
override def apply(that: Annotation): Boolean = {
(that.annotationType eq this.annotationType) && {
val thisEVPs = this.elementValuePairs
val thatEVPs = that.elementValuePairs
thatEVPs.size == thisEVPs.size &&
thisEVPs.forall(thisEVP => thatEVPs.exists(_ == thisEVP))
}
}
override def apply(sourceElement: ConcreteSourceElement): Boolean = {
sourceElement.annotations.exists(this(_))
}
override def toDescription(): String = {
elementValuePairs.
map(_.toJava).
mkString("@"+annotationType.toJava+"(", ",", ")")
}
}
/**
* Defines several additional factory methods to facilitate the creation of
* [[AnnotationPredicate]]s.
*
* @author Marco Torsello
*/
object AnnotatedWith {
type SomeClass = Class[_]
/**
* @param annotationType The type of the annotation. The given value must not be
* `java.lang.Void.TYPE`.
*/
def apply(
annotationType: SomeClass,
elementValuePairs: ElementValuePairs
): AnnotatedWith = {
new AnnotatedWith(Type(annotationType).asFieldType, elementValuePairs)
}
def apply(
annotationTypeName: BinaryString,
elementValuePairs: ElementValuePairs
): AnnotatedWith = {
val annotationType = ObjectType(annotationTypeName.asString)
new AnnotatedWith(annotationType, elementValuePairs)
}
def apply(
annotationTypeName: BinaryString,
elementValuePairs: Map[String, ElementValue]
): AnnotatedWith = {
new AnnotatedWith(
ObjectType(annotationTypeName.asString),
elementValuePairs.map(kv => ElementValuePair(kv._1, kv._2)).toSeq
)
}
def apply(
annotationTypeName: BinaryString,
elementValuePairs: (String, ElementValue)*
): AnnotatedWith = {
new AnnotatedWith(
ObjectType(annotationTypeName.asString),
elementValuePairs.map(kv => ElementValuePair(kv._1, kv._2)).toSeq
)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy