I'm trying to populate a POJO from a JSON that doesn't really match in any way and am having trouble getting this resolved. I can't change the JSON since it is an external service but I maybe able to modify the POJO if needed.
Below is an example JSON:
{"Sparse":[{"PixId":1,"PixName":"SWE","Description":"Unknown"},{"PixId":2,"PixName":"PUMNW","Description":"Power Supplement"}],"Status":0,"Message":null}
Below is the POJO:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Pix {
#JsonProperty("Description")
private String description;
#JsonProperty("PixId")
private int pixId;
#JsonProperty("PixName")
private String pixName;
// getters and setters
}
And here is my code to do the conversion:
ObjectMapper om = new ObjectMapper();
om.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
om.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<Pix> pixList = om.readValue(pixJson, new TypeReference<List<Pix>>() {});
The pixList contains only 1 element (should be 2 using the JSON above) and all the properties have not been populated. I'm using Jackson 1.9.9. Any ideas on how to get this to work? TIA.
You have to create new POJO class for main object which contains the List<Pix>. It could looks like this:
class Root {
#JsonProperty("Status")
private int status;
#JsonProperty("Message")
private String message;
#JsonProperty("Sparse")
private List<Pix> sparse;
//getters/setters
}
And now your deserialization code could looks like this:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
List<Pix> pixList = mapper.readValue(pixJson, Root.class).getSparse();
Related
How to insert JSON using quarkus-redis-client?
I tried writing the json as a String, but I don't know if it's correct.
#Singleton
public class EmployeeService {
#Inject
RedisClient redisClient;
public void insert(Employee employee) throws JsonProcessingException{
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(employee);
redisClient.set(Arrays.asList("employee", str ));
}
Employee get(String key) throws JsonMappingException, JsonProcessingException {
///Response res = redisClient.get(key);
String str = redisClient.get(key).toString();
ObjectMapper mapper = new ObjectMapper();
Employee emp = mapper.readValue(str, Employee.class);
return emp;
}
}
source code: https://github.com/alissonmelonascimento/quarkus-app-redis
Redis does not support JSON out of the box. It does only support the following datatypes. So it is OK to store JSON as a string.
But if you really need JSON support, you can try installing RedisJSON module in your server.
Do you can use this line to persist the information at Redis, the unique thing that you need to change is to replace the " to ' in your JSON content.
redisClient.set(Arrays.asList("employee", str ));
I am using the Jackson library to convert Java objects to YAML format. Based on the documentation I found on the Internet, I was able to quickly write a function that does the conversion.
I am seeking to convert the following classes to YAML:
public class RequestInfo
{
private String thePath;
private String theMethod;
private String theURL;
private List<ParamInfo> theParams = new ArrayList<>();
// getters and setters
}
public class ParamInfo
{
private String paramName;
private String paramType;
// getters and setters
}
Using Jackson's ObjectMapper, I can easily generate the YAML:
public String basicTest()
{
ObjectMapper theMapper = new ObjectMapper(new YAMLFactory());
RequestInfo info = new RequestInfo();
info.setThePath("/");
info.setTheMethod("GET");
info.setTheURL("http://localhost:8080/");
List<ParamInfo> params = new ArrayList<>();
params.add(new ParamInfo("resource","path"));
info.setTheParams(params);
String ret = null;
try
{
ret = theMapper.writeValueAsString(info);
}
catch(Exception exe)
{
logger.error(exe.getMessage());
}
return(ret);
}
The YAML I get is below:
---
thePath: "/"
theMethod: "GET"
theURL: "http://localhost:8080/"
theParams:
- paramName: "resource"
paramType: "path"
The YAML I get is OK, but it has some problems in my eyes. One probem is the "---" that it begins with. Another is the fact that I would like to be able to group the information in a manner similar to the YAML below:
RequestInfo:
thePath: "/"
theMethod: "GET"
theURL: "http://localhost:8080/"
theParams:
- paramName: "resource"
paramType: "path"
All of the examples I am seeing on the Internet use an Employee class, and talk about how to convert that class to YAML, but do not tell how to avoid the "---" (or change it into soething more descriptive). I also cannot find anything that tells how to group the YAML in the manner I describe.
Does anyone know how to do this? Is there a way to eliminate the "---", or create a name (like "RequestInfo") that groups together the translated data in an object?
You can ignore --- by disable YAMLGenerator.Feature.WRITE_DOC_START_MARKER..
If you want to wrap value under class name then u need to use #JsonRootName...
Try with this:
RequestInof class:
#JsonRootName("RequestInfo")
public class RequestInfo
{
private String thePath;
private String theMethod;
private String theURL;
private List<ParamInfo> theParams = new ArrayList<>();
// getters and setters
}
Test:
public String basicTest()
{
ObjectMapper theMapper = new ObjectMapper(new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER));
theMapper.enable(SerializationFeature.WRAP_ROOT_VALUE); RequestInfo info = new RequestInfo();
info.setThePath("/");
info.setTheMethod("GET");
info.setTheURL("http://localhost:8080/");
List<ParamInfo> params = new ArrayList<>();
params.add(new ParamInfo("resource","path"));
info.setTheParams(params);
String ret = null;
try
{
ret = theMapper.writeValueAsString(info);
}
catch(Exception exe)
{
logger.error(exe.getMessage());
}
return(ret);
}
I am using locationtech JTS library in spring boot with jackson as json serializer and a Jts-data-type module with supports serializing JTS geometry.The issue which i am facing is the axis order of coordinates when json is returned is long lat instead of lat long there is a solution on stackoverflow https://stackoverflow.com/a/29634389/1574921 i want to know if there is any other way to achieve this functionality instead of always applying InvertCoordinateFilter whenever i create a functionality.
Below is the code which i am using
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JtsModule());
double lat = 32.3456789;
double lng = 72.423434;
GeometryFactory gf = new GeometryFactory();
Point point = gf.createPoint(new Coordinate(lng,lat ));
String json = mapper.writeValueAsString(point);
System.out.println(json);
and the output is
{"type":"Point","coordinates":[72.423434,32.3456789]}
and i want output to be
{"type":"Point","coordinates":[32.3456789,72.423434]}
There is no way to tweak GeometrySerializer, since the order is hardcoded in lines 174-175.
In order to avoid writing a serializer by yourself, you could just copy GeometrySerializer and invert those two lines, but you would effectively not be using the official jts-data-type, and future modifications on the library would not be reflected in your copied serializer unless you do it manually.
Alternatively, just decorate the GeometrySerializer and use the InverseCoordinateFilter before calling it:
public static class CustomGeometrySerializer extends JsonSerializer<Geometry> {
private GeometrySerializer innerSerializer;
private InvertCoordinateFilter inverter = new InvertCoordinateFilter();
public CustomGeometrySerializer() {
this(new GeometrySerializer());
}
public CustomGeometrySerializer(GeometrySerializer innerSerializer) {
this.innerSerializer = innerSerializer;
}
#Override
public void serialize(Geometry value, JsonGenerator jgen,
SerializerProvider provider) throws IOException {
// Create a new Geometry to avoid mutating the original one
Geometry newValue = value.copy();
newValue.apply(inverter);
innerSerializer.serialize(newValue, jgen, provider);
}
private static class InvertCoordinateFilter implements CoordinateFilter {
public void filter(Coordinate coord) {
double oldX = coord.x;
coord.x = coord.y;
coord.y = oldX;
}
}
}
Now, instead of registering JtsModule, create a module yourself with your deserializer:
ObjectMapper mapper = new ObjectMapper();
SimpleModule inverseJtsModule = new SimpleModule();
inverseJtsModule.addSerializer(Geometry.class, new CustomGeometrySerializer());
mapper.registerModule(inverseJtsModule);
double lat = 32.3456789;
double lng = 72.423434;
GeometryFactory gf = new GeometryFactory();
Point point = gf.createPoint(new Coordinate(lng, lat));
String json = mapper.writeValueAsString(point);
System.out.println(json);
You can now safely serialize your geometries without explicitly inverting each one. For deserialization, you can use the same approach, decorating GeometryDeserializer.
I am trying to serialize a HashMap from Objects to Strings, but the specific Object has a reference to the current class leading to an infinite recursion, which doesn't seem to be solved with the usual JsonIdentifyInfo annotation. Here's an example:
public class CircularKey {
public void start() throws IOException {
ObjectMapper mapper = new ObjectMapper();
Cat cat = new Cat();
// Encode
String json = mapper.writeValueAsString(cat);
System.out.println(json);
// Decode
Cat cat2 = mapper.readValue(json, Cat.class);
System.out.println(mapper.writeValueAsString(cat2));
}
}
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "#id")
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#class")
class Mouse {
int id;
#JsonProperty
Cat cat;
}
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "#id")
#JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "#class")
class Cat {
int id;
#JsonSerialize(keyUsing = MouseMapKeySerializer.class)
#JsonDeserialize(keyUsing = MouseMapKeyDeserializer.class)
#JsonProperty
HashMap<Mouse, String> status = new HashMap<Mouse, String>();
public Cat() {
Mouse m = new Mouse();
m.cat = this;
status.put(m, "mike");
}
}
Here's the serializer/deserializer for the key:
class MouseMapKeySerializer extends JsonSerializer<Mouse> {
static ObjectMapper mapper = new ObjectMapper();
#Override
public void serialize(Mouse value, JsonGenerator generator,
SerializerProvider provider) throws IOException,
JsonProcessingException {
String json = mapper.writeValueAsString(value);
generator.writeFieldName(json);
}
}
class MouseMapKeyDeserializer extends KeyDeserializer {
static ObjectMapper mapper = new ObjectMapper();
#Override
public Mouse deserializeKey(String c, DeserializationContext ctx)
throws IOException, JsonProcessingException {
return mapper.readValue(c, Mouse.class);
}
}
If I switch the map to HashMap (String,Object) it works but I cannot change the original mapping. Any ideas?
It looks like you found your answer at http://jackson-users.ning.com/forum/topics/serializing-hashmap-with-object-key-and-recursion. This doesn't seem to be possible because:
Complex keys are tricky, and it is not a use case I ever considered. Then again, there is nothing specifically preventing use of standard components; main concern was just the limitations than JSON has (must be String-value, JsonParser/JsonGenerator expose keys as different tokens).
There is no explicit support for either polymorphic types or object ids for Object keys. Standard serializers/deserializers are mostly for relatively simple types that can be easily and reliably converted to/from Strings; numbers, Dates, UUIDs.
So: unlike with value handlers, where modular design (with separation of TypeSerializer/JsonSerializer) makes sense, I think what you need to do is to have custom (de)serializers that handle all aspects. You should be able to use code from existing value (de)serializers, type (de)serializers, but not classes themselves.
Your use case does sound interesting, but for better or worse, it is pushing the envelope quite a bit. :-)
I have the following code with a simple class and a method for writing and then reading:
ObjectMapper mapper = new ObjectMapper();
try{
DataStore testOut = new DataStore();
DataStore.Checklist ch1 = testOut.addChecklist();
ch1.SetTitle("Checklist1");
String output = mapper.writeValueAsString(testOut);
JsonNode rootNode = mapper.readValue(output, JsonNode.class);
Map<String,Object> userData = mapper.readValue(output, Map.class);
}
public class DataStore {
public static class Checklist
{
public Checklist()
{
}
private String _title;
public String GetTitle()
{
return _title;
}
public void SetTitle(String title)
{
_title = title;
}
}
//Checklists
private Vector<Checklist> _checklists = new Vector<Checklist>();
public Checklist addChecklist()
{
Checklist ch = new Checklist();
ch.SetTitle("New Checklist");
_checklists.add(ch);
return ch;
}
public Vector<Checklist> getChecklists()
{
return _checklists;
}
public void setChecklists(Vector<Checklist> checklists)
{
_checklists = checklists;
}
}
The line:
String output = mapper.writeValueAsString(testOut);
causes an exception that has had me baffled for hours and about to abandon using this at all.
Any hints are appreciated.
Here is the exception:
No serializer found for class DataStore$Checklist and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: DataStore["checklists"]->java.util.Vector[0])
There are multiple ways to do it, but I will start with what you are doing wrong: your naming of getter and setter method is wrong -- in Java one uses "camel-case", so you should be using "getTitle". Because of this, properties are not found.
Besides renaming methods to use Java-style names, there are alternatives:
You can use annotation JsonProperty("title") for GetTitle(), so that property is recognized
If you don't want the wrapper object, you could alternatively just add #JsonValue for GetTitle(), in which case value used for the whole object would be return value of that method.
The answer seems to be: You can't do that with Json. I've seen comments in the Gson tutorial as well, that state that some serialization just doesn't work. I downloaded XStream and spat it out with XML in a few minutes of work and a lot less construction around what I really wanted to persist. In the process, I was able to delete a lot of code.