How can I combine annotations in Java?
EDIT I was asking if I two annotations a and b, can I combine to a single annotations c?
If possible, how do I do that?
You cannot combine the annotations by e.g. annotating the annotations, unless the annotation consumer will process the meta-annotation tree explicitly. For example, Spring supports such feature for #Transactional, #Component and some other annotations (you may wish to have a look at SpringTransactionAnnotationParser#parseTransactionAnnotation()). Nice to have this feature in Java core, but alas...
However you can declare the common parent class that has a set of annotations you need and extend it. But this is not always applicable.
Assuming you want to have multiple annotations on a single element, you can just list them in sequence.
The Wikipedia page on Java annotations has quite a few useful examples, e.g.
#Entity // Declares this an entity bean
#Table(name = "people") // Maps the bean to SQL table "people"
class Person implements Serializable {
...
}
Related
I have an interface called StatsStore. I have 2 implementations of this store. An in-memory and an SQL implementation called InMemoryStatsStore and SqlStatsStore. In order to inject them I've create 2 annotations #InMemoryStore and #SqlStore. the injections are:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(StatsStore.class)
.annotatedWith(SqlStore.class)
.to(SqlStatsStore.class);
Now I want to add a new layer of annotation to separate between InMemoryStringStore and InMemoryNumberStore but I can't add more than one annotation to the binding lines e.g. the following does not compile:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.annotatedWith(NumberStoreAnnotation.class) // using named doesn't work as well
.to(InMemoryNumberStore.class);
How can I add more than one annotation without using a single named one which would be quite complicated the more layers I add to it?
The other solution I had in mind is Injecting twice:
bind(StatsStore.class)
.annotatedWith(InMemoryStore.class)
.to(InMemoryStatsStore.class);
bind(InMemoryStatsStore.class)
.annotatedWith(NumberStoreAnnotation.class)
.to(InMemoryNumberStore.class);
Thanks all.
As Amit said, you can't have more than one #BindingAnnotation apply to any given injection. Internally, Guice works like a Map<Key, Provider> where a Key is a possibly-parameterized class with an optional single annotation instance. However, because these are instances, you're welcome to create your own instantiable annotation that works the way Named works.
#Inject #InMemoryStore(NUMBER) StatsStore inMemoryNumberStore;
#Inject #SqlStore(STRING) StatsStore sqlStringStore;
// or
#Inject #Store(dataType=NUMBER, backend=SQL) sqlNumberStore;
The annotation must have the fields defined like so. (If you have one element named value, you can omit the property name per JLS 9.7.3.) Equal annotations are defined as in the Annotation.equals docs.
public enum DataType { NUMBER, STRING; }
public enum Backend { SQL, IN_MEMORY; }
#BindingAnnotation #Retention(SOURCE) #Target({ FIELD, PARAMETER, METHOD })
public #interface Store {
DataType dataType();
Backend backend();
}
That works nicely for #Provides, when you can invoke the annotation the same way you inject it, but how can you create a factory method for instances like Names.named? For that, you'll need to do one of the following:
Create an anonymous implementation, with accessors for each attribute as well as correct implementations of equals and hashCode. Note that the hashCode contract is much stricter than for Object, but you can get compatible implementations from Apache annotation utils or similar libraries.
Use AnnotationLiteral, which provides equals and hashCode implementations for arbitrary subclasses.
Use Google Auto or a similar code generator to generate code for a compatible implementation for you. Familiarity with this type of solution is particularly useful for Android and other memory-constrained environments for which reflection is slow, though such environments usually preclude you from using Guice. (#Qualifier annotations work the same way in other JSR-330 compatible dependency injection frameworks, though, including Dagger.)
If the above seems a little complicated, or if you want more complex logic than Guice's map-based implementation can accomplish, one alternative is to add a layer of indirection that you control:
public class StoreStore {
#Inject Provider<InMemoryNumberStore> inMemoryNumberStoreProvider;
// ...
// You can also inject the Injector to call getInstance with a class literal.
public StatsStore getStore(DataType dataType, Backend backend) {
// This can also be a switch or any other sort of lookup, of course.
if (dataType == NUMBER && backend == IN_MEMORY) {
return inMemoryNumberStoreProvider.get();
} // ...
}
}
You can't do that:
#BindingAnnotation tells Guice that this is a binding annotation. Guice will produce an error if ever multiple binding annotations apply to the same member.
You could use named bindings instead, or you should consider redesigning your solution.
Suppose I have already made class which I wish to persist. I can't change it's code, i.e. can't put any annotations inside. Also, class is not following bean convention.
I.e. it is arbitrary complex class I wish to persist.
Is it possible to write some sort of custom serializer and deserializer (don't know how to name it) in Hibernate, so that I be able to read these classes as usual POJOs?
Hello the first question is can I map a "fina class" the answer to this question is YES as long as you dont use Hibernate Enchancing or some sort of instrumentation.
Now second question. Bean not following Bean Conventions. I guess this means no getters and setters. You can have Attribute level access so this is again not a problem.
Is it possible to write custom serializer in Hibernate. The answer here is NO. Why ? Because Hibernate is not about Serialization hibernate is about SQL. There is no strict requirement that a Hibernate Entity should be serialize-able.
Even though Hibernate does not enforce serialization. Can I still make my final class serialize-able even though it does not implement Serializable or Eternalizeable. Yes you need to wrap it into class implementing Serializable or Externalizeable and implement the doRead doWrite methods yourself.
Serialization to JSON or XML - this is not part of Hibernate neither is part of JPA. Serialization to these two formats is defined as part of the Jaxb and Jax-rs specifications.
Have a look at hibernate UserType and CompositeUserType, with the well known EnumUserType example
Enums are a bit like your needs : final class, no getters nor setters. They are not complex though, so you might need a CompositeUserType that allows to map several columns for one Type, rather that a UserType.
Then you would use it like that in your class :
public class MyClass {
#Id
private Long id;
#Type(type = "com...MyCompositeUserType")
private ComplexFinalClassNotPojo complexObject;
}
I have some boolean fields in my JPA entities which are annotated in the following way:
#Column(length = 1)
#Type(type = "yes_no")
private final boolean myField;
Is it possible to create a combo-annotation (e. g. MyAnnotation) which combines both of this annotations?
#MyAnnotation
private final boolean myField;
How?
Obviously you could create an annotation that provides the equivalent of multiple other annotations.
Equally obviously no JPA provider will support it, since they will check for the javax.persistence annotations only (not that #Type is javax.persistence).
What you want is similar to CDI stereotypes - unfortunately, JPA does not support such a concept, therefore you must copy recurring annotations all over.
If you can afford to wrap your field into an object, you may mark it as #Embeddable and put your field into it - the annotations on that field will be copied wherever you embed that object into an entity. You may extend the annotations using #AnnotationOverrides. Obviously, the drawback of such solution is additional complexity when accessing the field in your entity.
When I looked among the standard constraints in Bean Validation API (JSR-303), I found the NotNull.List annotation. Its description is:
Defines several #NotNull annotations on the same element
This is valid syntax:
#NotNull.List({#NotNull, #NotNull})
private Object myObject;
But it makes no sense. Either the object is null or it is not. When would you use this annotation?
There are several other similar annotations like AssertFalse.List and AssertTrue.List.
You can have multiple #NotNull annotations that are mutually exclusive based on the group attribute.
#NotNull.List({#NotNull(groups=Foo.class,message="Some message!"),
#NotNull(groups=bar.class, message="Some other message!"})
private Object myObject;
I do agree it's a little silly for this example since only the payload and message can be affected, but it's probably there to remain consistent with the other annotations.
See here for more details.
As to the #NotNull case, multiple #NotNull annotations might be needed
for different validation groups as #dfb explained. But the same may be
accomplished by listing those groups in the groups attribute.
This is well explained here with test cases
In the bean validation API javadoc, for every constraint annotation,
there's a corresponding .List annotation. For example, for #NotNull,
there's #NotNull.List, for which JavaDoc says:
Defines several #NotNull annotations on the same element
What would you accomplish with multiple #NotNull annotations that you
cannot accomplish with one #NotNull?
I have java 1.7. Is there any way to group multiple annotations to single one. So that i annotate with single annotation and gets all the properties of all grouped multiple annotations. I want to avoid multiple annotation lines repeated every time.
Can we use the 3 annotation into one
Does java core libraries or others support this.
Thnx
No, that's not possible. An established idiom for this is to meta-annotate the #Combined annotation with its composing annotations:
#A
#B
#C
public #interface Combined {}
This pattern expresses that annotating an element with #Combined is equivalent to specifying #A, #B and #C at that element.
This of course requires the library consuming these annotations to be aware and make use of this pattern. That's e.g. the case for constraint annotations in Bean Validation or stereotypes in CDI.
I'm not sure if this is what you're looking for, but CDI provide stereotype annotations.