I basically would like to turn this:
#Entity
#Table(name = "edu_course")
public class EduCourse {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="course_seq")
#SequenceGenerator(
name="course_seq",
sequenceName="course_sequence",
allocationSize=20
)
private int id;
}
into this:
#Entity
#Table(name = "edu_course")
public class EduCourse {
#SequenceId(name = "course")
private int id;
}
I tried different things but I always end up with the complier warning: "This annotation is not applicable to target 'annotation class'".
Is that somehow possible to do?
It is not possible to create meta-annotations in the current spec.
Take a look at #Id annotation:
#Target({METHOD, FIELD})
#Retention(RUNTIME)
public #interface Id {}
ANNOTATION_TYPE is not listed as a possible target, which is why you receive "This annotation is not applicable to target 'annotation class'" error.
There is an open issue Allow type level annotations to be used as meta-annotations #43 created in 2013, sadly it is still not implemented in 2023.
Related
i'm trying to encapsulate the where clause annotation inside another one so i don't have to duplicate this where clause into many entities because the where clause could change in the futur and i don't want to update 50 entities one by one but only the annotation default value. the problem is that my where clause isn't detected, can someone please help me ?
#Target({TYPE, FIELD, METHOD})
#Retention(RUNTIME)
#Where(clause = "companyId=10154")
public #interface WhereCompanyClause {
}
#Entity
#Table(name="Group_")
#Getter
#WhereCompanyClause
public class Group{}
#Entity
#Table(name = "LayoutSet")
#Getter
#WhereCompanyClause
public class LayoutSet
I have been reading a lot about using enums as parameters in queries. I have some queries in my project that use the value from these enums as parameters.
For example:
public enum YesNo {
Y, N
}
Query:
select ent
from
Entity ent
where
ent.id = :id
and ent.deleted = project.path.example.YesNo.N
Entity:
#Entity
public class Entity{
Long id;
#Enumerated(EnumType.STRING)
YesNo deleted;
}
The above works correctly as expected.
However, when I have the following:
interface Commons{
interface MostCommonTypesofAnimals {
long DOG = 1L;
long CAT = 2L;
}
}
Query
select a
from
Animal a
where
a.id = :id
and a.type = project.path.example.Commons.MostCommonTypesofAnimals.DOG
Entity
#Entity
public class Animal{
Long id;
Type type;
}
#Entity
public class Type{
public Long id;
}
It does not work telling me that the path is incorrect even though it is actually correct.
Is there any work around? Or interface values cannot be mapped? Can anyone provide me an example that works? I could not find anything similar.
Please note that this is just an example to illustrate the situation., those are not the real names that I am using or anything.
For using enum while using hibernate / jpa (based on your tags), you should use annotation in your Pojo class.
#Enumerated(EnumType.ORDINAL)
In your example, something like:
#Entity
#Table(name = "tableName")
public class entityName {
#Enumerated(EnumType.ORDINAL)
private YesNo yesNoEnum;
}
The annotation can go here or in the getter, as you prefer.
You can find more info here
ps: for yes or no I suggest you using a boolean value, not an enum
I'm placing an annotated field with #Version on it in all my JPA domain classes, however this just seems like additional boiler plate. Is there a way to get around this perhaps via configuration?
TIA,
Ole
As far as the JPA specification tells us you can't change the #Version annotation via "configuration". You either use #Version in your program code or you don't.
Referring to the official JPA specification (final version, JPA 2.1) in Section 3.4.2 (page 90) we find:
An entity is automatically enabled for optimistic locking if it has a property or field mapped with a Version mapping.
[...]
If only some entities contain version attributes, the persistence provider runtime is required to check those entities for which version attributes have been specified. The consistency of the object graph is not guaranteed, but the absence of version attributes on some of the entities will not stop operations from completing.
However, you can use the concept of inheritance to provide the #Versiononly in one spot via an abstract base class. This class you be written as follows:
#MappedSuperclass
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class AbstractBaseEntity {
public static final long INVALID_OBJECT_ID = -42;
#Version
private int version;
#Id
#SequenceGenerator(name = "sequence-object", sequenceName = "ID_MASTER_SEQ")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence-object")
#Column(name = "id")
protected Long objectID = INVALID_OBJECT_ID;
public final int getVersion() {
return version;
}
#Override
public long getObjectID() {
return objectID;
}
// ... maybe other methods or fields ...
}
Thus, all your #Entity annotated sub-classes that inherit from AbstractPersistentEntity are provided with both properties: (i) objectIDand (ii) version at once. For instance, class SomeClass can be written as:
#Entity
public class SomeClass extends AbstractBaseEntity /*implements SomeInterface*/ {
// ... specific methods or fields ...
}
For details on the use of #MappedSuperclass see also this answer.
Hope it helps.
I have this hibernate class with annotations:
#Entity
public class SimponsFamily{
#Id
#TableGenerator(name = ENTITY_ID_GENERATOR,
table = ENTITY_ID_GENERATOR_TABLE,
pkColumnName = ENTITY_ID_GENERATOR_TABLE_PK_COLUMN_NAME,
valueColumnName = ENTITY_ID_GENERATOR_TABLE_VALUE_COLUMN_NAME)
#GeneratedValue(strategy = GenerationType.TABLE, generator = ENTITY_ID_GENERATOR)
private long id;
...
}
Since I don´t won´t to annotate every id field of my classes that way, I tried to create a custom anotation:
#TableGenerator(name = ENTITY_ID_GENERATOR,
table = ENTITY_ID_GENERATOR_TABLE,
pkColumnName = ENTITY_ID_GENERATOR_TABLE_PK_COLUMN_NAME,
valueColumnName = ENTITY_ID_GENERATOR_TABLE_VALUE_COLUMN_NAME)
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface EntityId {
#GeneratedValue(strategy = GenerationType.TABLE, generator = ENTITY_ID_GENERATOR)
public int generator() default 0;
#Id
public long id() default 0;
}
so that I can use this annotation in my class:
#Entity
public class SimponsFamily{
#EntityId
private long id;
...
}
I do have to write the #Id and the #GeneratedValue annotions on field level since they do not support the TYPE RetentionPolicy. This solutions seems to work.
My questions:
How are the field level annotations in my custom annotations(and values) transferred to my usage of EntityId annotation?
What about the default values which I set in my custom annotation, are they used since I do not specify attributes at the usage?
It is a preferred way to use annotations on field level in annotations?
I think I can aswer your third question.
One common way to do what you want (avoid duplicating ID mapping) is to create a common superclass that holds the annotated id and version (for optimistic locking) fields, and then have all persistent objects extend this superclass.
To ensure the superclass is not considered an Entity on its own, it must be annotated with #MappedSuperclass.
Here is a sample (sorry for typos, I don't have an IDE at hand right now) :
#MappedSuperclass
public class PersistentObject {
#Id // Put all your ID mapping here
private Long id;
#Version
private Long version;
}
#Entity
public class SimpsonsFamily extends PersistentObject {
// Other SimpsonFamily-specific fields here, with their mappings
}
Has:
#MappedSuperclass
class Superclass {
#Id
#Column(name = "id")
protected long id;
#Column(name="field")
private long field;
}
and
#Entity
class Subclass extends Superclass {
}
How to annotate inherited id with #GeneratedValue and field with #Index within Subclass?
How to annotate inherited id with #GeneratedValue and field with #Index within Subclass?
AFAIK, you can't. What you can do is overriding attributes and associations (i.e. change the column or join column) using the AttributeOverride and AssociationOverride annotations. But you can't do exactly what you're asking.
For the GeneratedValue, consider using XML mapping to override the strategy if you don't want to declare it in the mapped superclass.
For the Index (which is not a standard annotation by the way), did you actually try to declare it at the table level using Hibernate's Table annotation instead (I'm assuming you're using Hibernate)?
#Table(appliesTo="tableName", indexes = { #Index(name="index1", columnNames=
{"column1", "column2"} ) } )
creates the defined indexes on the
columns of table tableName.
References
JPA 1.0 Specification
Section 2.1.9.2 "Mapped Superclasses"
Section 9.1.10 "AttributeOverride Annotation"
Section 9.1.11 "AttributeOverrides Annotation"
Section 9.1.12 "AssociationOverride Annotation"
Section 9.1.13 "AssociationOverrides Annotation"
Hibernate Annotations Reference Guide
2.4. Hibernate Annotation Extensions
Chapter 3. Overriding metadata through XML
As for #GeneratedValue, it is possible to do like this:
#MappedSuperclass
class Superclass {
#Id
#Column(name = "id")
#GeneratedValue(generator = "id_generator")
protected long id;
#Column(name = "field")
private long field;
}
#Entity
#SequenceGenerator(name = "id_generator", sequenceName = "id_seq")
class Subclass extends Superclass {
}
You might be able to do this if you apply the annotations to the accessor methods instead. (I haven't tried this, so I can't guarantee that it'll work.)
#MappedSuperclass
public class Superclass {
#Id
#Column(name = "id")
public long getId() {
return id;
}
.
#Entity
public class Subclass extends Superclass {
#GeneratedValue
public long getId() {
return super.getId();
}
Just in case anyone else searches for this, I used the following code which adds in some overhead, but for processing Field annotations only shouldn't add that much:
private List<Field> getAllFields() {
List<Field> fieldList = new ArrayList<Field>();
// Add all fields from the current class
fieldList.addAll(Arrays.asList(mElement.getClass().getDeclaredFields()));
// Use an index to iterate over mElement's parent types
Class clazz = mElement.getClass();
// Get any fields from the parent class(es)
while (clazz.getSuperclass() != null) {
fieldList.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
// Set it to that parent class
clazz = clazz.getSuperclass();
}
return fieldList;
}
The returned list would contain all fields for all parent and child classes with mElement being the object you are searching for annotations from. Hope this helps.