Is there a way to declare #Convert directly onto the ENUM - java

I am using #Convert(converter = CoverConverter.class) to convert attribute value before storing it on a database and vice versa. I have to declare this annotation at each an every place where I am using a particular ENUM. Let's call it TestENUM for now.
But this particular ENUM is used at more than 100 places and I am not sure that other developers in my group will remember to add this annotation when they use this ENUM.
So I was wondering if there was a way that I can annotate an ENUM directly in a way that wherever it is used it will be converted before being persisted into database and vice versa when fetched from database through JPA
so example:
#Convert(convert = true)
public enum TestENUM {}

You should be able to create a Converter and use the autoApply property:
If the autoApply element is specified as true, the persistence
provider must automatically apply the converter to all mapped
attributes of the specified target type for all entities in the
persistence unit except for attributes for which conversion is
overridden by means of the Convert annotation (or XML equivalent).
http://docs.oracle.com/javaee/7/api/index.html?javax/persistence/Convert.html
#Converter(autoApply = true)
public class MyEnumConverter implements Converter{
}

Related

How can I introspect a Java class's Jackson PropertyNamingStrategy when it is explicitly set by #JsonNaming?

I have some code which reads rows from a database and using Jackson ObjectMapper to convert them to objects. I am trying to make this as generic as possible, to serve as a library function.
For some particular object classes, the PropertyNamingStrategy is set explicitly via the #JsonNaming annotation to something other than how my row schema is defined (just the name casing is different, conceptually the names and data are the same).
I can use an intermediate library to convert the expected property names after I get them from the row schema to how the #JsonNaming annotation defines them. But that is very specific to one class.
Is there a way I can introspect a class type to find out what its PropertyNamingStrategy is? Or use ObjectMappper (or another Jackson utility) to find out, prior to doing the actual deserialization? That way my caller would not need to know or care about this when using my code.
Is there a way I can introspect a class type to find out what its
PropertyNamingStrategy is?
Yes, you can use the the SerializationConfig#introspectClassAnnotations method that returns a BeanDescription, gets its info and create an AnnotatedClass that will be inspected by the JacksonAnnotationIntrospector instance like below:
#JsonNaming(PropertyNamingStrategy.KebabCaseStrategy.class)
public class MyClass {}
AnnotatedClass acl = mapper.getSerializationConfig()
.introspectClassAnnotations(MyClass.class)
.getClassInfo();
JacksonAnnotationIntrospector jai = new JacksonAnnotationIntrospector();
//in this case it will prints class
//com.fasterxml.jackson.databind.PropertyNamingStrategy$KebabCaseStrategy
//In case of no annotation over the class the value will be null
System.out.println(jai.findNamingStrategy(acl));

How to Inject values from a property file into JSR Custom Annotation

I have a spring component that validates the values of an Entity Class,
One of the variables has a Custom Annotation whose values are supposed to be loaded from the property file, currently it says that Attribute must be constant
Here is the sample code.
I know that Spring allows to fetch properties like this
#Value("${allowedNames}")
private String names;
But I have an entity with one of the variables annotated by custom validator interface i.e. #NameValidationDefinition. I would like to pass the values from the properties file to the annotation but it gives compile time error that Attribute must be Constant which I understand as I know that
Annotations take only constants or final and static declared primitives or Strings
public Class Person {
#NameValidationDefinition(values = names)
private String name;
}
What I want to know is that is there a workaround for this to make it work?
The value from the properties file is by default casted to String but still when I create the Entity and initialize the variable as static final and pass the String in the Constructor, I get the same compile time error.
I would appreciate any kind of help on this.
You cannot have variables in annotations. That's not a limitation of Bean Validation, but of the JVM itself. See also Which types can be used for Java annotation members?
Note, in the Spring example you are giving the value is a string with a special "key" ${allowedNames} which later on gets interpolated. That's different from the value of the annotation being an actual variable as your code implies.

What is the purpose of AccessType.FIELD, AccessType.PROPERTY and #Access

I just want to know what is the difference between all these annotations. Why are we using these... means they have no effect especially field level and property level.
And what is the purpose of using mixed level annotation like:
#Entity
#Access(AccessType.FIELD)
class Employee {
// why their is a field level access
private int id;
// whats the purpose of transient here
#Transient
private String phnnumber;
// why its a property level access
#Access(AccessType.property)
public String getPhnnumber() {
return "1234556";
}
}
what exactly this class says?
By default the access type is defined by the place where you put your mapping annotations. If you put them on the field - it will be AccessType.FIELD, if you put them on the getters - it will be AccessType.PROPERTY.
Sometimes you might want to annotate not fields but properties (e.g. because you want to have some arbitrary logic in the getter or because you prefer it that way.) In such situation you must define a getter and annotate it as AccessType.PROPERTY.
As far as I remember, if you specify either AccessType.FIELD or AccessType.PROPERTY on any of the entity fields / methods you must specify the default behaviour for the whole class. And that's why you need to have AccessType.FIELD on the class level (despite that AccessType.FIELD is the default value.)
Now, if you wouldn't have #Transient on the phnnumber field, the JPA would provide you with a 3 columns table:
id,
phnnumber,
getphnnumber.
That's because it would use AccessType.FIELD for all of the entity fields (id and phnnumber) and, at the same time, it'd use AccessType.PROPERTY for your getter (getPhnnumber()).
You'll end with phone number mapped twice in the database.
Therefore, the #Transient annotation is required - it means that the entity won't store the value of the field in the underlying storage but the value returned by your getter.

is it possible to make all fields of an object #Transient by default

I have a base Entity class which will be derived in more than a hundred of a subclasses.
In order to be sure that persisted fields will be the ones I want (and not the users of that base class), I want to declare this JPA entity as setting all fields as transient by default.
How is it possible ?
If you don't put #MappedSuperclass on your class you are extending from, the class properties will never by persisted.
You can provide getter methods for certain properties, and place the annotations on the properties instead of the fields. The #Id annotation determines if you want the fields or the properties. In JPA 2 you can also use the #Access annotation.

Read ENUM and its fields from a database (JPA)

I have a model object that's in fact an enum with fields and getters:
#Entity
public enum Type {
TYPE1, TYPE2, TYPE3, TYPE4;
#Column
private Long id;
#Column
private String name;
...
public String getName() {
return this.name;
}
...
}
It compiles and runs fine. However, if I call a getter method, it returns null (it doesn't load any values stored in the database). Is this the standard behavior? Is there a way to make JPA load them?
I'd say there is some misconception in this aproach:
Entities represent objects that can be stored in the database. In this case, the database (or any other persistent store) defines which instances are available.
Enums represent a fixed set of constants that are defined in source code. Thus the class itself defines which constants are available. In addition, it's generally bad practice to change the values of an enum, i.e. the name or id in your case.
You see that they are two quite different concepts which should be treated differently.
To store enums in entities (where the enum is a field of that entity), you could either use #Enumerated and store the name or ordinal of the enum, or (what we do more often) store one of the fields (we mostly use the id) and provide conversion methods.
If you want to store configurable "constants" in the database you might try and use plain entities for that, make the constructor private (Hibernate and other JPA providers should be able to deal with that) and provide an alternative implementation of the Enum class (you can't use the enum keyword though).
Have you looked into the #Enumerated annotation? I haven't ever tried to use it within an enum itself, however it works quit well binding a class property to an enum.
enum Type{TYPE1, TYPE2}
#Column(name="type")
#Enumerated(EnumType.STRING)
public Type getType(){return type;}
public void setType(Type t){type = t;}
If JPA cannot be made to handle this, you could add a public Type valueOf(long id) method to your enum class which you use as a factory to instantiate enum instances representing the values in your legacy table.

Categories