Serialization is a lot of boilerplate. I was wondering if I could use annotations to write that for me, thus allowing the structure of the object to double as its on-disk format.
I know Jackson exists but ObjectMapper feels too magical and I'd like to just have something like this:
#SynthSerializer
public class Foo {
public final String name;
public final String description;
public Foo(String name, String description) {
this.name = name;
this.description = description;
}
}
//Following code generated at compile time by #SynthSerializer:
public class FooSerializer: implements Serializable {
//Boilerplate, you know the drill
}
Incidentally, from what I understand modifying source code using annotations is a hack, but creating altogether new classes (like in my example) is an intended use case for annotations. That's true, yes?
Anyway, is this kind of generation possible with annotations? Is this a sane way to do something like this? And do annotation processors that already do something like this exist?
Related
I have a JSON String and I want to deserialize it to a Java object with a interface data member. The Java object looks like this:
public class Person {
private String id;
private String name;
private AddressInterface addr;
}
Both the Person and the AddressInterface are third party classes, so I can't make any changes to them.
When I used the following to deserialize the JSON string,
objectMapper.readValue(json_file, Person.class)
I got the following exception. It's because the object mapper doesn't know how to deserialize the AddressInterface field. Can someone let me know how to deserialize the string into an Person object in this case? Many Thanks.
abstract types either need to be mapped to
concrete types, have custom deserializer,
or be instantiated with additional type information
AddressInterface is an interface and is considered abstract. Both classes Foo and Bar could implement AddressInterface, but it would be unable to tell which one the data should be deserialized as.
Random idea which might work:
Put the interface in a wrapper. I'm just guessing since I don't know the library context, but maybe something like this. Also there's probably a few typos in here, but it shows the general idea.
public class AbstractSerializable<T> implements Deserialize {
private final String className;
private T obj;
public AbstractSerializable(T obj) {
this.obj = obj;
this.className = obj.getClass().getCardinalName();
}
#Override
public AbstractSerializable deserialize(ObjectMapper objectMapper) {
String clazz = input.readNext(String.class);
return objectMapper.readNext(Class.forName(clazz));
}
}
Edit: This would probably break if you tried to put a lambda in it.
Edit 2: #Hadi Note is correct that Gson would make some things easier, however it would run into the same issues. I did find this article which explains how to fix it when using Gson. It uses a similar approach to my answer, but they have a much better explanation.
With GSON library you can get rid of the boilerplate codes!
You can use GSON library in the link below!
https://www.tutorialspoint.com/gson/gson_quick_guide.htm
the problem is deserializing AddressInterface property because its an interface and I think objectMapper is trying to initilaize it's default constructer like bellow
addr = new AddressInterface();
you can create an empty concrete class which inherits the AddressInterface and use it instead of AddressInterface
public class Adress implements AddressInterface {
...
}
public class Person {
private String id;
private String name;
private Adress addr;
}
I am considering moving from Hibernate to jOOQ but I can't find e.g.
how to have Pattern-Constraints on a String like this in Hibernate:
#NotEmpty(message = "Firstname cannot be empty")
#Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
private String firstname;
How would I do that in jOOQ?
The "jOOQ way"
The "jOOQ way" to do such validation would be to create either:
A CHECK constraint in the database.
A trigger in the database.
A domain in the database.
After all, if you want to ensure data integrity, the database is where such constraints and integrity checks belong (possibly in addition to functionally equivalent client-side validation). Imagine a batch job, a Perl script, or even a JDBC statement that bypasses JSR-303 validation. You'll find yourself with corrupt data in no time.
If you do want to implement client-side validation, you can still use JSR-303 on your DTOs, which interact with your UI, for instance. But you will have to perform validation before passing the data to jOOQ for storage (as artbristol explained).
Using a Converter
You could, however, use your own custom type by declaring a Converter on individual columns and by registering such Converter with the source code generator.
Essentially, a Converter is:
public interface Converter<T, U> extends Serializable {
U from(T databaseObject);
T to(U userObject);
Class<T> fromType();
Class<U> toType();
}
In your case, you could implement your annotations as such:
public class NotEmptyAlphaNumericValidator implements Converter<String, String> {
// Validation
public String to(String userObject) {
assertNotEmpty(userObject);
assertMatches(userObject, "^[a-zA-Z0-9_]*$");
return userObject;
}
// Boilerplate
public String from(String databaseObject) { return databaseObject; }
public Class<String> fromType() { return String.class; }
public Class<String> toType() { return String.class; }
}
Note that this is more of a workaround, as Converter hasn't been designed for this use-case, even if it can perfectly implement it.
Using formal client-side validation
There's also a pending feature request #4543 to add more support for client-side validation. As of jOOQ 3.7, this is not yet implemented.
I recommend you don't try to use jOOQ in a 'hibernate/JPA' way. Leave the jOOQ generated classes as they are and map to your own domain classes manually, which you are free to annotate however you like. You can then call a JSR validator before you attempt to persist them.
For example, jOOQ might generate the following class
public class BookRecord extends UpdatableRecordImpl<BookRecord> {
private String firstname;
public void setId(Integer value) { /* ... */ }
public Integer getId() { /* ... */ }
}
You can create your own domain object
public class Book {
#NotEmpty(message = "Firstname cannot be empty")
#Pattern(regexp = "^[a-zA-Z0-9_]*$", message = "First Name can only contain characters.")
private String firstname;
public void setId(Integer value) { /* ... */ }
public Integer getId() { /* ... */ }
}
and map by hand once you've retrieved a BookRecord, in your DAO layer
Book book = new Book();
book.setId(bookRecord.getId());
book.setFirstname(bookRecord.getFirstname());
This seems quite tedious (and ORM tries to spare you this tedium) but actually it scales quite well to complicated domain objects, in my opinion, and it's always easy to figure out the flow of data in your application.
I think I need to create a specialist ObjectMapper and cannot find any sample code to start the process.
The creator of the JSON is using .Net and public properties and therefore uses field names with an uppercase initial. I am parsing the JSON into POJOs so I would like to use a lowercase initial.
At their end:
public class Facet
{
public string Name { get; set; }
public string Value { get; set; }
}
At my end I must therefore have:
public class Facet {
public String Name;
public String Value;
}
I would much prefer:
public class Facet {
public String name;
public String value;
}
Am I right that this could be done with an ObjectMapper?
Your first issue can be addressed very simply with the #JsonProperty annotation:
// java-side class
public class Facet
{
#JsonProperty("Name")
public String name;
#JsonProperty("Value")
public String value;
}
Now the ObjectMapper will match up the differently-cased field names. If you don't want to add annotations into your classes, you can create a Mix-in class to stand in for your Facet:
public class FacetMixIn
{
#JsonProperty("Name")
public String name;
#JsonProperty("Value")
public String value;
}
objectMapper.getDeserializationConfig().addMixInAnnotations(Facet.class, FacetMixIn.class);
This will achieve the same thing, without requiring additional annotations in your Facet class.
Instead of annotating each field, the Jackson ObjectMapper can be configured to use a built-in or custom PropertyNamingStrategy, to apply a consistent translation between Java property/field names and JSON element names.
For example:
myObjectMapper.setPropertyNamingStrategy(PascalCaseStrategy);
This problem could be solved from Jackson 2.5.0 like this:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
From the javadoc:
com.fasterxml.jackson.databind.MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES
Feature that will allow for more forgiving deserialization of incoming
JSON. If enabled, the bean properties will be matched using their
lower-case equivalents, meaning that any case-combination (incoming
and matching names are canonicalized by lower-casing) should work.
Note that there is additional performance overhead since incoming
property names need to be lower-cased before comparison, for cases
where there are upper-case letters. Overhead for names that are
already lower-case should be negligible however.
Feature is disabled by default.
Since:
2.5
Just a quick update as I was looking for same answer and a code snippet objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
Since v 2.13 use builder:
XmlMapper xmlMapper = (XmlMapper) getObjectMapper();
private ObjectMapper getObjectMapper() {
return XmlMapper.builder()
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
.build();
}
In playframework, it uses javassist library to let the public fields of a class can be used as property.
See the example:
public class User {
public String name;
}
User user = new User();
user.name = "Freewind"
System.out.println(user.name);
In compilation time, play enhanced the bytecode with javassist, the final code is similar to:
public class User {
private String name;
public String getName() { return this.name; };
public void setName() { this.name = name; };
}
User user = new User();
user.setName("Freewind");
System.out.println(user.getName());
You can see not only the field name has getter and setter, but also the invocations of it changed to getters and setters.
I wonder if there is any other way to do the same (use other things than javassist)?
I found Annotation Processing Tool, but I'm not sure it can do it.
Or aspectj? Or something else?
You can look at Project Lombok, which does something similar, but with annotations. With project lombok you do need to use the getters and setters in your own code.
Not without other tools.
Unlike C#, Java does not support properties.
Is it somehow possible to annotate a Java Method in that way that i later can give another Method a Field Identifier or something like that, so that this Method can call the right one?
I know that normally you would do this with interfaces, but in my case this would be a immense count of interfaces... I need to use this in Entity Classes for my Database (and i'm not allowed to use a ORM Mapper)
For example: I have the Entity
public class Account{
private String username;
private String password;
private String name;
private String mail;
public void setUserName(String username){
this.username = username;
}
public String getUserName(){
return username;
}
[all other getter/Setter...]
}
Now i want to tell a Method that it need to validate a Field, for example the username field.
The Method that does should look like this:
public void validateField(XXX Field, Entity entity) throws ValidationFailedException, EmptyFieldException;
where XXX is somehow the FieldIdentifier.
Is that in any way possible in Java?
My only guess it that i Use public static final ìnt stuff in there to give every field a Method or so...
What do you use? I don't see any annotations from which I can guess your framework. If you use Hibernate, you can use something like #NotNull or something else, or even do your custom validation:
This is how you would go with your example:
public class Account{
#NotNull(message="This field should not be null")
private String username;
#NotBlank(message="This string should not be empty or null")
private String password;
private String name;
private String mail;
public void setUserName(String username){
this.username = username;
}
public String getUserName(){
return username;
}
[all other getter/Setter...]
}
http://silentwalker.wordpress.com/2009/04/07/custom-validation-in-hibernate/
You can also create your own annotations without using any framework and use them #prepersist or whatever. Basically the sky is the limit.
P.S Since you don't want to use any non internal code, here is how you can approach:
First, you can define an annotation
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface NotNull{
public String message() default "";
}
Then, before persisting the class, you would inspect its fields:
So, you have something like this:
Field[] classFields = yourObjectPrePersist.getClass().getDeclaredFields();
for (int i = 0; i < classFields.length; i++) {
classFields[i].setAccessible(true);//take notice that if you use a SecurityManager, you should work around it
if (classFields[i].getAnnotation(NotNull.class) != null) {
Object value = classFields[i].get(yourObjectPrePersist);
//here check if value is null or not and then return the message
if (value == null) {
throw new SomeException(((NotNull) classFields[i].getAnnotation(NotNull.class)).message());
}
}
}
Annotations don't seem like the right solution to the problem you describe.
One possibility would be to pass in the name of the field that needs to be validated, then used the java.beans.BeanInfo class to access the field values of the Entity. This will allow you to access arbitrary attributes of an object without having to deal with all of the complexity of reflection.
You can use reflection for this; see the documentation for java.lang.reflect.Field. The caller can pass in the field-name as a string, and validateField can use something like Field f = entity.getClass().getField(fieldName).
But this is not usually a great idea . . . reflection is awesome, but it requires a lot of boilerplate code, and you pay a high price in maintainability. (You also pay a performance penalty, though in my experience the maintainability penalty is much worse than the performance penalty.) Personally I use reflection a lot in test code (it can help in writing extremely comprehensive tests), and I make use of frameworks like Spring and Hibernate that depend on reflection, but I avoid it in my own production code.
You could use a generic interface
public interface Field {
public String getValue();
}
and call your validate method with anonymouse classes
validator.validate(new Field() {
return account.getUsername()
});
(or with old java)
validator.validate(new Field() {
public String getValue() {
return account.getUsername();
}
});
Otherwise what about using java.lang.Methode directly?
P.S.: Sorry for the quote, stackoverflow did not let me post my text directly, said it was not formatted correctly :-/