I want to be able to annotate a class with a list of 2 types of annotations which are related in function, but are completely different in arguments. The order of this list matters though. I have tried looking for this already, but was unable to find any references to this (I was not sure what to call this).
Edit:
What I want to be able to do in the end:
//place holder for example (Abstract)
public #interface A {
}
#Target(PARAMETER)
public #interface B extends A {
//Gets stuff
Class type();
int key();
}
#Target(PARAMETER)
public #interface FlaggedListOfA extends A {
//List of A
A[] set();
}
//Goal is to have annotation that does this
#Target(METHOD)
public #interface ImportantFunc {
A[] dataForA() default {};
String[] names();
int property() default 0;
//etc.
}
//End goal:
public class SomeImportantClass {
#ImportantFunc(dataForA = {#B(...), #B(...}, ...)
public void doStuff() {
}
//So I can have an end goal of this (Order matters, may contain repeats,
//and has unknown length!)
#ImportantFunc(dataForA = {#B(...), #FlaggedListOfA(#B(...), #B(...))}, ...)
public void doStuffB() {
}
#ImportantFunc(dataForA = {#FlaggedListOfA(#B(...)), #FlaggedListOfA(#B(...), #B(...))}, ...)
public void doStuffC() {
}
#ImportantFunc(dataForA = {#FlaggedListOfA(#B(...), #FlaggedListOfA(#B(...), #B(...))), #B(...)}, ...)
public void doStuffD() {
}
}
Reflections to get all uses of ImportantFunc (Ex: 100 uses of it) in package and uses this data to choose which function to use. The annotation is to help with the reflection since once it gets the data from #ImportantFunc, it then converts it to input for a library which does the actual choosing of which function to execute (this is internal and can not be modified). This could also be achieved with much longer and more annoying ways, but I was hoping to use annotations to simplify the process of defining all of these functions.
Edit:
Another way this could be solved is finding a way to group two annotations together.
Being able to do this would not be completely ideal, but would definitely make this much more workable:
public #interface Example {
AnyTypeOfAnnotation[] set();
}
One kludgy way to do this is to actually make A be a union of B and C. This means it has all the fields of both B and C, but you only ever use it as either a B or a C.
Here's a working example.
import java.lang.annotation.*;
enum NoType {;}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface A {
Class<?> data() default NoType.class; // field from B
int dataA() default 0; // field from C
String dataB() default ""; // field from C
}
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface D {
A[] value() default {};
}
class Foo {}
class Bar {}
class Example {
#D({
#A(data = Bar.class),
#A(dataA = 5, dataB = "Bla"),
#A(data = Foo.class)
})
public static void main(String[] args) throws Exception {
for (A a : Example.class.getMethod("main", String[].class)
.getAnnotation(D.class).value()) {
if (a.data() != NoType.class) {
System.out.printf("B(%s)%n", a.data());
} else {
System.out.printf("C(dataA = %d, dataB = \"%s\")%n",
a.dataA(), a.dataB());
}
}
}
}
The output of that program is:
B(class Bar)
C(dataA = 5, dataB = "Bla")
B(class Foo)
Of course, it's not a very pretty solution, but it does work.
Not sure this would be sufficient for your use case:
public #interface A {
}
public #interface B extends A {
//Gets stuff
Class data();
}
public #interface C extends A {
//Gets different stuff related to same goal
int dataA();
String dataB();
}
public #interface D {
Class<? extends A>[] order();
}
#B(Bar.class)
#C(dataA = 5, dataB = "Bla")
#D(order = {B.class, C.class})
public class SomeImportantClass {
}
This method uses D annotation as a mean to retain annotation order. The bad part is that you cannot add multiple annotations of the same type.
There is another method that makes A, B and C into normal classes.
public abstract class AnnotationAttribute {
public abstract Class<?>[] getDataTypes();
public abstract Object[] getData();
}
public class B extends AnnotationAttribute {
#Override public Class<?>[] getDataTypes() {
return new Class<?>[] {Foo.class, Bar.class};
}
#Override public Object[] getData() {
return new Object[] {new Foo(), new Bar()};
}
}
public #interface D {
Class<? extends AnnotationAttribute>[] data() default {};
}
#D(data = {B.class});
public class Test {
}
This method requires you to create one class for one concrete attribute type. This is because annotations have to be compile-time constant, and referencing via Class requires you to define the class out in code.
Related
How to choose CDI java bean base on annotation, then the annotation poses table of arguments?
The problem is easier to show using an example than to describe.
Assume that for each object of type Problem we have to choose proper solution.
public class Problem {
private Object data;
private ProblemType type;
public Object getData() { return data; }
public void setData(Object data) { this.data = data; }
public ProblemType getType() { return type; }
public void setType(ProblemType type) { this.type = type;}
}
There are few types of problems:
public enum ProblemType {
A, B, C;
}
There are few solutions:
public interface Solution {
public void resolve(Problem problem);
}
like FirstSolution:
#RequestScoped
#SolutionQualifier(problemTypes = { ProblemType.A, ProblemType.C })
public class FirstSolution implements Solution {
#Override
public void resolve(Problem problem) {
// ...
}
}
and SecondSolution:
#RequestScoped
#SolutionQualifier(problemTypes = { ProblemType.B })
public class SecondSolution implements Solution {
#Override
public void resolve(Problem problem) {
// ...
}
}
The solution should be chosen based on annotation #SolutionQualifier:
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface SolutionQualifier {
ProblemType[] problemTypes();
public static class SolutionQualifierLiteral extends AnnotationLiteral<SolutionQualifier> implements SolutionQualifier {
private ProblemType[] problemTypes;
public SolutionQualifierLiteral(ProblemType[] problems) {
this.problemTypes = problems;
}
#Override
public ProblemType[] problemTypes() {
return problemTypes;
}
}
}
By SolutionProvider:
#RequestScoped
public class DefaultSolutionProvider implements SolutionProvider {
#Inject
#Any
private Instance<Solution> solutions;
#Override
public Instance<Solution> getSolution(Problem problem) {
/**
* Here is the problem of choosing proper solution.
* I do not know how method {#link javax.enterprise.inject.Instance#select(Annotation...)}
* works, and how it compares annotations, so I do no know what argument I should put there
* to obtain proper solution.
*/
ProblemType[] problemTypes = { problem.getType() };
return solutions.select(new SolutionQualifier.SolutionQualifierLiteral(problemTypes));
}
}
And in the last one there is a problem:
I do not know how method javax.enterprise.inject.Instance#select(Annotation...) works internally, and how it compares annotations, so I do no know what argument I should put there to obtain proper solution. If there appear a problem of type A table ProblemType[] will consist of one argument, while FirstSolution.class is annotated with #SolutionQualifier having two arguments, so therefore I will not get the proper Instance.
I didn't find a way to resolve it using CDI API, instead:
I created another enum:
public enum SoultionType {
A(ProblemType.A, ProblemType.C),
B(ProblemType.A);
//...
SoultionType(ProblemType problems...) {
// ...
}
public static SoultionType getByProblemType(ProblemType problem) {
// ...
}
}
Changed so SolutionQualifier has only SoultionType field inside, so there is no problem with the comparison.
I'm trying to code, for fun, a class that use an annotion with another annotation inside, but I don't understand how to code.
My code
First annotation
#interface FirstAnnotation {
String author();
}
Second annotation, contains the first annotation
public #interface SecondAnnotation {
FirstAnnotation inside();
int version();
}
Class with annotation
#FirstAnnotation(
author = "alessandro"
)
#SecondAnnotation(
version = 1,
inside = /*Compilation code: what code? FirstAnnotation, this??*/
)
public class GeneralClass {
/*
* a generic method
*/
public void method() {
System.out.println("method");
}
}
What I have to put in row with string Compilation code, as reference to actual value of FirstAnnotation in the class?
You class should be:
#SecondAnnotation(
version = 1,
inside = #FirstAnnotation(
author = "alessandro"
)
)
public class GeneralClass {
/*
* a generic method
*/
public void method() {
System.out.println("method");
}
}
Given the following abstract class:
public abstract class BaseVersionResponse<T extends BaseVO> {
public abstract void populate(T versionVO);
}
and the following child class:
public class VersionResponseV1 extends BaseVersionResponse<VersionVOV1>
{
protected String testFieldOne;
protected String testFieldTwo;
public String getTestFieldOne() {
return testFieldOne;
}
public void setTestFieldOne(String value) {
this.testFieldOne = value;
}
public String getTestFieldTwo() {
return testFieldTwo;
}
public void setTestFieldTwo(String value) {
this.testFieldTwo = value;
}
#Override
public void populate(VersionVOV1 versionVO) {
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
I desire to do something like this from a calling method:
public void getVersionInfo(String version) {
BaseVO versionVO = null;
BaseVersionResponse<? extends BaseVO> baseVersionResponse = null;
baseVersionResponse = createVersionResponse(version);
versionVO = createVersionVO(version);
baseVersionResponse.populate(versionVO);
}
where createVersionResponse(...) and createVersionVO(...) look like this:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version) {
BaseVersionResponse<? extends BaseVO> specificVersionResponse = null;
if (version.equalsIgnoreCase("V1")) {
specificVersionResponse = new VersionResponseV1();
} else if (version.equalsIgnoreCase("V2"))
specificVersionResponse = new VersionResponseV2();
return specificVersionResponse;
}
public BaseVO createVersionVO(String version) {
BaseVO versionVO = null;
if (version.equalsIgnoreCase("V1")) {
versionVO = new VersionVOV1();
} else if (version.equalsIgnoreCase("V2"))
versionVO = new VersionVOV2();
return versionVO;
}
and VersionVOV1 looks like this:
public class VersionVOV1 extends BaseVO {
private String fieldOne = null;
private String fieldTwo = null;
private String fieldThree = null;
public String getFieldOne() {
return fieldOne;
}
public void setFieldOne(String fieldOne) {
this.fieldOne = fieldOne;
}
public String getFieldTwo() {
return fieldTwo;
}
public void setFieldTwo(String fieldTwo) {
this.fieldTwo = fieldTwo;
}
public String getFieldThree() {
return fieldThree;
}
public void setFieldThree(String fieldThree) {
this.fieldThree = fieldThree;
}
}
My problem arises when I try to compile this line of code:
baseVersionResponse.populate(versionVO);
in getVersionInfo(...). I'm getting a message that looks like this:
The method populate(capture#3-of ?) in the type BaseVersionResponse is not applicable for the arguments (BaseVO)
on the populate method above.
My thought was (which is apparently incorrect) that since the baseVersionResponse is, at this point in the code, actually a specific child instance, that the class would know exactly which populate method to call from that specific child class.
What am I doing wrong here? Is there a better way to do this if this isn't the correct approach?
Thank you for your time!
Ok, I took a better look at this today. The problem is that the wildcard, while the right way to go, precludes you from doing:
BaseVO versionVO = createVersionVO(version);
Because the populate call wants an extension of BaseVO, not an actual BaseVO, which doesn't qualify. That means you can't pass that versionVO variable directly.
So, to keep the type checking in place, which I think is good because you'll always want an implementation, leave pretty much everything as-is above, and change your BaseVersionResponse class to something like:
public abstract class BaseVersionResponse<T extends BaseVO> {
public T getVersion(BaseVO versionVO) {
try {
return (T) versionVO;
} catch (ClassCastException e) {
throw new IllegalArgumentException();
}
}
public abstract void populate(BaseVO versionVO);
}
So, populate method now takes a BaseVO, and there's a new getVersion method to do some explicit casting for us. This should be ok since we know that the factory will always supply the right thing, but if another caller doesn't, an IllegalArgumentException is thrown.
Now, in your response class implementation, change the populate method accordingly:
public void populate(BaseVO version) {
VersionVOV1 versionVO = getVersion(version);
this.setTestFieldOne(versionVO.getFieldOne());
this.setTestFieldTwo(versionVO.getFieldTwo());
}
So, we've changed the populate method to take BaseVO, and the getVersion method does the casting for us. All the other type checks still apply, and we're good to go.
The casting makes it feel not as clean, but for the factory approach you're using, it's really the only way (I can think of) to keep the guarantees made by the type declarations and the code pattern in tact.
Hope that helps!
If you just take out the capture of type (the "<?>"), and leave it unchecked, it should work just fine. Even using type Object would have compiled.
But, given your specific example, what you probably want is the method:
public BaseVersionResponse<?> createVersionResponse(String version)
Changed to:
public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version)
Then, instead of using
BaseVersionResponse<?>
use
BaseVersionResponse<? extends BaseVO>
Since you know that the return type will be one of those things that implements the interface/class.
I am using Java7. I have a custom annotation created and annotated it on an Marker interface.
#SomeName(name="ABC")
public interface Bank{
}
Below is the class which implements the above interface.
public class BankImpl implements Bank{
//some code
}
Now i have a method in a separate class which takes above class as an input:
public void someMethod(Class class){
//Here i need to get the custom annotation value
}
Above method is called as below:
someMethod(BankImpl.class);
Now inside someMethod() how can i get the annotation value?
Thanks!
String someMethod(Class<Bank> clazz){
SomeName sn = clazz.getAnnotation(SomeName.class);
return sn.name();
}
You only need the Class of the inteface to get everything of the Annotation which is annotated on the interface.
The problem is that the class itself does not have the annotation, therefore you'll get a null value when asking for the annotation. You really need to look into all the hierarchy of the class (i.e. superclass and interfaces):
import java.util.*;
import java.lang.annotation.*;
#Retention(value=RetentionPolicy.RUNTIME)
#interface SomeName {
String name();
}
#SomeName(name = "ABC")
interface Bank {
}
class BankImpl implements Bank {
}
public class Test {
public void someMethod(Class c) {
Annotation annotation = c.getAnnotation(SomeName.class);
if (annotation == null) {
LinkedList<Class> queue = new LinkedList<Class>();
queue.addLast(c.getSuperclass());
for (Class cc : c.getInterfaces())
queue.addLast(cc);
while (!queue.isEmpty()) {
c = queue.removeFirst();
annotation = c.getAnnotation(SomeName.class);
if (annotation != null)
break;
}
}
if (annotation == null)
System.out.println("No such annotation !");
else
System.out.println("name is: " + ((SomeName)annotation).name());
}
public static void main(String... args) {
Test test = new Test();
test.someMethod(BankImpl.class);
}
}
I don't understand how I can retrieve the Enum values in an annotation processor.
My annotation is a custom Java Bean Validation annotation:
#StringEnumeration(enumClass = UserCivility.class)
private String civility;
On my annotation processor, I can access to instances of these:
javax.lang.model.element.AnnotationValue
javax.lang.model.type.TypeMirror
javax.lang.model.element.TypeElement
I know it contains the data about my enum since I can see that in debug mode. I also see ElementKind == Enum
But I want to get all the names for that Enum, can someone help me please.
Edit: I don't have access to the Class object of this Enum, because we are in an annotation processor, and not in standart Java reflection code. So I can't call Class#getEnumConstants() or EnumSet.allOf(MyEnum.class) unless you tell me how I can get the Class object from the types mentioned above.
I found a solution (this uses Guava):
class ElementKindPredicate<T extends Element> implements Predicate<T> {
private final ElementKind kind;
public ElementKindPredicate(ElementKind kind) {
Preconditions.checkArgument(kind != null);
this.kind = kind;
}
#Override
public boolean apply(T input) {
return input.getKind().equals(kind);
}
}
private static final ElementKindPredicate ENUM_VALUE_PREDICATE = new ElementKindPredicate(ElementKind.ENUM_CONSTANT);
public static List<String> getEnumValues(TypeElement enumTypeElement) {
Preconditions.checkArgument(enumTypeElement.getKind() == ElementKind.ENUM);
return FluentIterable.from(enumTypeElement.getEnclosedElements())
.filter(ENUM_VALUE_PREDICATE)
.transform(Functions.toStringFunction())
.toList();
}
The answer given by Sebastian is correct, but if you're using Java 8 or above, you can use the following (cleaner) approach than using Google Guava.
List<String> getEnumValues(TypeElement enumTypeElement) {
return enumTypeElement.getEnclosedElements().stream()
.filter(element -> element.getKind().equals(ElementKind.ENUM_CONSTANT))
.map(Object::toString)
.collect(Collectors.toList());
}
Here's a complete example. Note the use of getEnumConstants on the enum values.
public class Annotate {
public enum MyValues {
One, Two, Three
};
#Retention(RetentionPolicy.RUNTIME)
public #interface StringEnumeration {
MyValues enumClass();
}
#StringEnumeration(enumClass = MyValues.Three)
public static String testString = "foo";
public static void main(String[] args) throws Exception {
Class<Annotate> a = Annotate.class;
Field f = a.getField("testString");
StringEnumeration se = f.getAnnotation(StringEnumeration.class);
if (se != null) {
System.out.println(se.enumClass());
for( Object o : se.enumClass().getClass().getEnumConstants() ) {
System.out.println(o);
}
}
}
}
This will print out:
Three
One
Two
Three