Instruct Jackson to serialize from given method - java

I'm using Jackson library vs 2.6.3. I would like to define the serialization method inside a class and I would like to instruct Jackson to call this method when an object is serialized.
E.g.
public interface AClass {
default String toJSON(){
return "{JSON}";
}
}
and then I have
public class AnotherClass {
AClass aClass;
}
When I serialize AnotherClass, I "pretend" that method toJson from AClass is called to return the JSON view of the object.
Is there any annotation that I can use on AClass?

Yes, this is possible using #JsonValue and #JsonRawValue annotations. Here is an example:
public class JacksonValue {
public interface AClass {
#JsonValue
#JsonRawValue
default String toJSON(){
return "{\"JSON\":true}";
}
}
public static class AnotherClass {
#JsonProperty
AClass aClass = new AClass() {};
}
public static void main(String[] args) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(new AnotherClass()));
}
}
Output:
{"aClass":{"JSON":true}}

Related

How to use mixin to ignore a field when using ObjectMapper?

class Apple{
#JsonProperty("colour")
public String colour;
#JsonProperty("dummy_params")
public DummyParams dummyParams;
}
public abstract class AppleMixin{
#JsonIgnore
#JsonProperty("dummy_params")
public DummyParams dummyParams;
}
I am trying to ignore dummyParams field when using ObjectMapper
class Tester{
public static void main(){
Apple app = new Apple();
app.setColor("red");
app.setDummyParams(new DummyParams("1","2"));
ObjectMapper objecMapper = new ObjectMapper();
objecMapper.addMixIn(Apple.class, AppleMixin.class);
String result = objecMapper.writeValueAsString(exec);
}
}
I am using com.fasterxml.jackson.databind.ObjectMapper
Expected Result : {"colour": "red"}
Actual Result : {"colour":"red", "dummyParams":{"dummyOne" :1,"dummyTwo":2}}
The mixin is not working.Am I doing wrong?

Ignore properties marked with specific annotation

I have ObjectMapper instance:
ObjectMapper mapper = new ObjectMapper();
In runtime want to serialize instance of class. What is the class the program doesn't known. It's object instance of parameterized type T.
How to ignore all properties (fields and getters) which marked specified annotation (javax.persistence.Id) ?
Example:
public static class PojoTest {
#Id
public String idTest;
public String id;
}
public void serialize(Object object) {
ObjectMapper objectMapper = new ObjectMapper();
// TODO ignore property mark #Id annotation
Map<Object, Object> map = objectMapper.convertValue(object, Map.class);
assertFalse(map.containsKey("idTest"));
}
public void test() {
PojoTest pojoTest = new PojoTest();
pojoTest.id = "foo";
pojoTest.idTest = "bar";
serialize(pojoTest);
}
You can implement a new com.fasterxml.jackson.databind.AnnotationIntrospector class where you can extend hasIgnoreMarker method:
static class IdIgnoreAnnotationIntrospector extends AnnotationIntrospector {
#Override
public Version version() {
return new Version(1,0,0,"Ignore #Id", "group.id", "artifact.id");
}
#Override
public boolean hasIgnoreMarker(AnnotatedMember m) {
return hasIdAnnotation(m);
}
boolean hasIdAnnotation(AnnotatedMember member) {
return member.getAnnotation(Id.class) != null;
}
}
Now you need to register this introspector:
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(AnnotationIntrospector.pair(new JacksonAnnotationIntrospector(), new IdIgnoreAnnotationIntrospector()));
Now you can ignore all fields marked with #Id annotation.

How to read annotation which is declared over a Java object?

How to read annotation which is declared over an object.
For e.g
Annotation :
AuthorInfo.java
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface AuthorInfo {
String author() default "Dushyant Kumar";
String login() default "dushyantashu";
}
What I am trying to do :
Book.java
#Data
public class Book {
private int serialNo;
private String review;
}
Main.java
public class Main {
#AuthorInfo (
author = "Barry Allen",
login = "theflash"
)
private static Book book = new Book();
public static void main(String[] args) {
showAnnotation(book);
}
private static void showAnnotation(Object object) {
// How to get values of annotation declared over this object.
}
}
My usecase is to generate this generic showAnnotation() method, that's why param is Object. How to achieve this? From what I explored, I only got ways to read annotation if it's declared over a class, or declared over a member of a class. Isn't there a way where given an object, if some annotation is present over it can be read?
Thanks
You can give a try with generics and reflection. Assume the Book class is annotated with AuthorInfo like below:
#AuthorInfo(author = "Ram", login = "ram")
public class Book {
}
Suppose if you want to know whether AuthorInfo is present in the object of Book, you can do like below. This is straight forward solution to know whether specific annotation is present in an object.
public class TestAnnotation {
public static void main(String[] args) {
Book book = new Book();
showAnnotation(book);
}
private static <T> void showAnnotation(T t) {
Class<? extends Object> aClass = t.getClass();
if (aClass.isAnnotationPresent(AuthorInfo.class)) {
System.out.println("AuthorInfo annotation present");
AuthorInfo authorInfo = aClass.getAnnotation(AuthorInfo.class);
System.out.println(authorInfo.author());
System.out.println(authorInfo.login());
}
}
}
Suppose, if you want to know all annotations on that object, something like below helps:
private static <T> void showAnnotation(T t) {
Class<? extends Object> aClass = t.getClass();
for (Annotation annotation : aClass.getAnnotations()) {
System.out.println(annotation.toString());
}
}
You can retrieve the object class and then explore it. Via Reflection you could get its fields and methods also, and check if any has annotations on it.
Annotations can be read using Reflection API. Like
Class<Main> clazz = Main.class;
Method[] methods = clazz.getDeclaredMethods();
Field[] fields = clazz.getDeclaredFields();
for (Method method : methods) {
Annotation[] annotation = method.getDeclaredAnnotations();
}
for (Field field : fields) {
//This will get #AuthorInfo annotation on book
Annotation[] annotation = field.getDeclaredAnnotations();
//This will get #Data annotation on Book class
Annotation[] annotationsOnFieldClass = field.getClass().getDeclaredAnnotations();
}
clazz.getDeclaredAnnotations();

Jackson deserialize string value that contains valid json

Suppose I have the following JSON data:
{
"header": "some value",
"message": "{\"field1\": \"abc\", \"field2\": 123}"
}
Is it possible to adjust the annotations on OuterClass so the message field will be parsed as an InnerClass object?
public class InnerClass {
#JsonProperty("field1")
public void setField1(String value) {/* do stuff */}
#JsonProperty("field2")
public void setField2(Integer value) {/* do stuff */}
}
public class OuterClass {
#JsonProperty("message")
public void setMessage(InnerClass obj) {/* do stuff */}
}
Ideally I would like the calling code to look something like:
ObjectMapper mapper = new ObjectMapper();
OuterClass obj = mapper.readValue(jsonStr, OuterClass.class);
Structure your outer class to have a property of the other class that represents the nested JSON, like:
public class OuterClass {
#JsonProperty("header")
private String header;
#JsonProperty("message")
private InnerClass message;
//getters & setters
}
Once I added some complexity, the accepted answer would not work. I kept getting the error:
Can not instantiate value of type [simple type, InnerClass] from JSON String; no single-String constructor/factory method (through reference chain: InnerClass)
I ended up using the following approach
public class OuterClass {
public InnerClass message;
#JsonCreator
public OuterClass (Map<String,Object> delegate) throws IOException {
String json = (String)delegate.get("Message");
ObjectMapper mapper = new ObjectMapper();
this.message = mapper.readValue(json, InnerClass.class);
}
}

how to only serialize properties annotated with a custom annotation

We use jackson throughout our application to serialize and deserialize Java objects to JSON. It works great.
Is it possible, perhaps through a custom serializer, to serialize only properties of a Java object that are Annotated with a custom annotation?
So, given the custom annotation:
public #interface SpecialField {}
And the following bean
public SomeBean {
#SpecialField
private Object propertyIncluded;
private Object propertyExcluded;
}
What would a custom serializer (or some equivalent mechanism) look like to serialize propertyIncluded (using the normal jackson object mapper) and ignore propertyExcluded?
We can't use standard jackson annotations (#JsonIgnore) in this use case because it would break our other serialization uses cases in the application.
While this might not be quite what your looking for, It is possible to make the jackson engine serialize objects differently via some tweaking. In my example below I create two types of serializers which will or wont serialize a field marked as transient.
import java.io.Serializable;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.map.ObjectMapper;
public class Test {
public static void main(String[] args) throws Exception {
ISerializer d = new Doesnt();
ISerializer o = new Observes();
SomeObject obj = new SomeObject();
System.out.println("Doesnt: " + d.serialize(obj));
System.out.println("Observes: " + o.serialize(obj));
}
public static class Doesnt implements ISerializer<SomeObject> {
#Override
public String serialize(SomeObject o) throws Exception {
ObjectMapper om = new ObjectMapper();
om.setVisibilityChecker(
om.getSerializationConfig().
getDefaultVisibilityChecker().
withFieldVisibility(JsonAutoDetect.Visibility.ANY).
withGetterVisibility(JsonAutoDetect.Visibility.ANY));
return om.writeValueAsString(o);
}
}
public static class Observes implements ISerializer<SomeObject> {
#Override
public String serialize(SomeObject o) throws Exception {
ObjectMapper om = new ObjectMapper();
om.setVisibilityChecker(
om.getSerializationConfig().
getDefaultVisibilityChecker().
withFieldVisibility(JsonAutoDetect.Visibility.ANY).
withGetterVisibility(JsonAutoDetect.Visibility.NONE));
return om.writeValueAsString(o);
}
}
public interface ISerializer<T> {
public String serialize(T o) throws Exception;
}
public static class SomeObject implements Serializable {
private static final long serialVersionUID = 745063791749142843L;
private transient String myVar = "Transient";
private String myOther = "Not Transient";
public String getMyVar() {
return myVar;
}
public void setMyVar(String myVar) {
this.myVar = myVar;
}
public String getMyOther() {
return myOther;
}
public void setMyOther(String myOther) {
this.myOther = myOther;
}
}
}
output:
Doesnt: {"myVar":"Transient","myOther":"Not Transient"}
Observes: {"myOther":"Not Transient"}
I would think it would be fairly easy to change serializers to extend the JsonSerializer class, and do something similar in them.

Categories

Resources