I'm writing rest services using jersey and jackson. I have something like this example
import com.mkyong.Track;
@Path("/json/metallica")
public class JSONService {
@GET
@Path("/get")
@Produces(MediaType.APPLICATION_JSON)
public Track getTrackInJSON() {
Track track = new Track();
track.setTitle("Enter Sandman");
track.setSinger("Metallica");
return track;
}
@POST
@Path("/post")
@Consumes(MediaType.APPLICATION_JSON)
public MyResponse createTrackInJSON(Track track) {
return new MyResponse().setResult(true);
}
}
But in my case, the classe Track is not a simple pojo bean.I use a Map to save my data and I create a method to generate json from my object and a constructor to parse json data.
public class JsonObject {
Map<String, String> data = new HashMap<>();
public String toJson(){
return "";
}
}
public class Track extends JsonObject {
public Track(String json) {
//Parse json
// [...]
}
public Track(JsonNode node) {
//Parse node
// [...]
}
public String getTitle() {
if(data.containsKey("title"))
return data.get("title");
return "";
}
public void setTitle(String title) {
data.put("title", title);
}
public String getSinger() {
if(data.containsKey("singer"))
return data.get("singer");
return "";
}
public void setSinger(String singer) {
data.put("singer", singer);
}
@Override
public String toString() {
return "Track [title=" + getTitle() + ", singer=" + getSinger() + "]";
}
public String toJson() {
return "{\"title\": \"" + getTitle() + "\", \"singer\": \"" + getSinger() + "\"}";
}
}
public class MyResponse extends JsonObject {
public boolean getResult() {
if(data.containsKey("result"))
return (boolean) data.get("result");
return false;
}
public MyResponse setResult(boolean value) {
data.put("result", value);
return this;
}
@Override
public String toString() {
return "{\"result\": " + getResult() + "}";
}
}
So my question is: is it possible to create actions before and after the method call to tell to jackson how to generate or parse my object ? using annotation and/or creating an ObjectReader or something like that ?
Thanks
Edit :
Thanks peeskillet.
I'm not sure @JsonAnyGetter et @JsonAnySetter are my solution. I have many objects that extend JsonObject and I want to keep it with getters and setters for my rest api.
So I created a generic JsonSerializer:
public class MyObjectSerializer extends JsonSerializer<JsonObject> {
@Override
public void serialize(JsonObject value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeRaw(value.toJson());
}
}
Then I add this annotation to MyResponse object.
@JsonSerialize(using = MyObjectSerializer.class)
public class MyResponse ...
I wish I did not have to add this annotation in each objects and that was done automatically during rest service return but it works fine and it's not so restrictive.
Now I have another problem with deserialization. I want a generic deserializer calling constructor with parameter JsonNode. But how do I know what class call?
I saw a parameter "as" in @JsonDeserialize annotation.
@JsonDeserialize(using = MyObjectDeserializer.class, as=Track.class)
But I don't find how get this information in the JsonDeserializer. Any idea ?
(Maybe I could open another thread for this question)