Adversaria is a tiny library which provides a few tools to make it easier to work with static annotations in Scala, by making them available through typeclass interfaces.
- access all annotations on a type through a typeclass
- resolve a typeclass instance only if a type has an annotated field
- makes annotations more useful and accessible in Scala
- no macro code is required to use annotations
The nature of annotations in Scala is that they are very rarely the best solution for any task. The can, however, be convenient in certain circumstances, and this small domain is where Adversaria aims to help.
Currently three use cases are supported:
- getting all the annotations applied to a particular type
- finding the parameter of a case class to which a particular annotation has been applied
- getting all the annotations applied to a particular case class field
The list of supported use cases may grow as additional suggestions are received.
If we were to define the following annotations,
import scala.annotation.StaticAnnotation final case class id() extends StaticAnnotation final case class count(n: Int) extends StaticAnnotation
we could apply them to some case classes, such as,
@count(10) case class Company(name: String) case class Person(name: String, @id email: String)
Perhaps we would like to find out the annotations on
Company. We can get this information by requesting an implicit
TypeMetadata[Company] value, and accessing its
annotations field, like so,
import adversaria._ val info = implicitly[TypeMetadata[Company]] println(info.annotations) > List(count(10))
TypeMetadata implicit should resolve for any type, regardless of whether it has any annotations or not. Its
annotations method will return a list of annotations on that case class.
Another supported use case is to find the field of a case class which has been annotated with a particular annotation, if and only if that annotation exists. We use the
FindMetadata typeclass for this. It takes two type parameters: the type of the annotation, and the type to check for, respectively,
import adversaria._ val idField = implicitly[FindMetadata[id, Person]] println(idField.get(Person("John Smith", "email@example.com))) > firstname.lastname@example.org
However, attempting to resolve such an implicit on a case class which has no field annotated with that annotation, for example,
val idField = implicitly[FindMetadata[id, Company]]
will fail with at compiletime with the message,
adversaria: could not find a parameter annotated with type @id
Adversaria is classified as fledgling. Propensive defines the following five stability levels for open-source projects:
- embryonic: for experimental or demonstrative purposes only, without guarantee of longevity
- fledgling: of proven utility, seeking contributions, but liable to significant redesigns
- maturescent: major design decisions broady settled, seeking probatory adoption and refinement of designs
- dependable: production-ready, subject to controlled ongoing maintenance and enhancement; tagged as version
- adamantine: proven, reliable and production-ready, with no further breaking changes ever anticipated
Adversaria’s source is available on GitHub, and may be built with Fury by cloning the layer
fury layer clone -i propensive/adversaria
or imported into an existing layer with,
fury layer import -i propensive/adversaria
A binary is available on Maven Central as
com.propensive:adversaria-core_<scala-version>:0.18.0. This may be added to an sbt build with:
libraryDependencies += "com.propensive" %% "adversaria-core" % "0.18.0"
We suggest that all contributors read the Contributing Guide to make the process of contributing to Adversaria easier.
Please do not contact project maintainers privately with questions, as other users cannot then benefit from the answers.
Adversaria is copyright © 2017-20 Jon Pretty & Propensive OÜ, and is made available under the Apache 2.0 License.