Serialize JSON Subclasses Information in Java - java

I need some help with one JSON serialization Problem.
I have one class like this:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorFormula("type")
#JsonSubTypes({ #JsonSubTypes.Type(value =TextFileCardEntity.class, name = "textCard"),
#JsonSubTypes.Type(value = MultipleChoiceFileCard.class, name = "choiceCard")#JsonSubTypes.Type(value = MultipleChoiceFileCard.class, name = "choiceCard")})
public class FileCardEntity extends ResourceEntity implements Cloneable {
#NotNull
#JsonIgnore
private FileCardType type;
private Date expirationDate;
.....
I also have two classes that extends of FileCardEntity:
#JsonTypeName(value = "textCard")
public class TextFileCardEntity extends FileCardEntity {
#Lob
#Type(type = "org.hibernate.type.TextType")
private String question;
#Lob
#Type(type = "org.hibernate.type.TextType")
private String answer;
.......
AND
#Entity
#DiscriminatorValue("1")
#JsonTypeName(value = "choiceCard")
public class MultipleChoiceFileCard extends FileCardEntity {
#Lob
#Type(type = "org.hibernate.type.TextType")
private String question;
#Lob
#Type(type = "org.hibernate.type.TextType")
private String crib;
......
I use the next Code in order to deserialize the information:
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
final ObjectWriter typedWriter = mapper.writerWithType(mapper.getTypeFactory().constructCollectionType(List.class, classElement));
System.out.println(typedWriter.writeValueAsString(elements));
Where elements is: List<?> elements
When I deserialize information from Server about TextFileCardEntity, I get:
[{"textCard":{"status":"ACTIVE","lastModified":1366293513200,"expirationDate":0.....
That is ok
When I attempt serialize information about TextFileCardEntity for example to Server, the code sends:
[{"FileCardEntity":{"status":"ACTIVE","lastModified":1366378327069,"shared":false,"orderID":0........
That is not ok because I need the syntax to be similar has in the deserialization information
--> [{"textCard":{"status".... and not [{"FileCardEntity":{"status"....
What can I do?

Related

Post request transform int field to string automatically

I'm doing a dummy app of a hostpital. The problem I'm having is that, I'm trying to verify that when a Patient is created, the fields passed are of the correct type, but whenever I POST an Int in a String field, it doesn't fail and just transform the Int to String. The field I'm trying to make fail is "surname", which by the definition of the Patient class, is a String.
If I do this (I pass a number to the "surname" field):
{
"name": "John",
"surname": 43,
"sickness": "headache"
}
It just transforms 43 into a String by the time its in the Controller method.
Here we have the Patient object:
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
public class Patient implements Serializable {
private static final long serialVersionUID = 4518011202924886996L;
#Id
//TODO: posible cambiar luego la generationType
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "patient_id")
private Long id;
#Column(name = "patient_name")
#JsonProperty(required = true)
private String name;
#Column(name = "patient_surname")
#JsonProperty(required = true)
private String surname;
#Column(name = "patient_sickness")
#JsonProperty(required = true)
private String sickness;
}
And this is the controller class:
#Controller
#Path("/patient")
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public class PatientController {
#POST
#Path("")
public ResponseEntity<Object> postPatient(final Patient patient) {
ResponseEntity<Object> createdPatient = patientBusiness.createPatient(patient);
return new ResponseEntity<Patient>(createdPatient.getBody(), createdPatient.getStatusCode());
}
EDIT 1:
Following the "clues" and closing the circle of attention, I tried modifying the ObjectMapper, but my configuration isn't applying. I'm still getting the error from above.
This is the config class:
#Configuration
public class JacksonConfig {
#Bean
#Primary
public ObjectMapper getModifiedObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, false);
mapper.coercionConfigFor(LogicalType.Integer).setCoercion(CoercionInputShape.String, CoercionAction.Fail);
return mapper;
}
}
Even added the property to the application.yml, but still nothing:
spring:
jackson:
mapper:
allow-coercion-of-scalars: false
Any help is appreciated. Thx.
In the end I referred to this post to do a deserializer and a module to just have it along all the program, not just the field I want not to be transformed.
Disable conversion of scalars to strings when deserializing with Jackson

Spring elasticsearch how to generate mapping for all the fields?

I have a Person class:
#Document(indexName = "person")
#Data
#EqualsAndHashCode(callSuper = true)
public class Person extends BaseEntity implements Serializable {
#Field(type=FieldType.Keyword)
private String firstName;
#Field(type=FieldType.Keyword)
private String lastName;
#MultiField(
mainField = #Field(type = FieldType.Keyword),
otherFields = {
#InnerField(type = FieldType.Text, suffix = "ngrams", analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
})
private String fullName;
#Field
private String maidenName;
}
I have an existing code that creates an index during startup:
final IndexOperations indexOperations = this.elasticsearchOperations.indexOps(clazz);
indexOperations.putMapping();
Now, I have a requirement to generate mappings from it and create mappings once. Can somebody help how can I integrate it with the existing code to include mappings of the fields to make them static?
Just check if the index needs to be created, if so, create it and write the mapping:
indexOperations = operations.indexOps(entityClass);
if (!indexOperations.exists()) {
indexOperations.createWithMapping();
}

JsonPropertyOrder not ordering correctly

so as you can see from the title my #JsonPropertyOrder is not ordering how I want... this is my class(see code bellow) and everything is ordered good except the zpp attribute, it goes between "spravce" and "ziskatele". I tried to rename it reorder it and its totally ignored.Thank you for all the answers :)
(JacksonXML ver 2.9.8)
#JacksonXmlRootElement(localName = "xmlroot")
#JsonPropertyOrder({"cnt-unik-id","kod-produktu","frekvence","datum-sjednani",
"pocatek","konec","spravce","ziskatele","objekty-unik-id","udaje","objekty-all","adresy","zpp"})
public class ContractDetail{
#JacksonXmlProperty(localName = "zpp")
private Integer zpplID;
#JacksonXmlProperty(localName = "cnt-unik-id")
private Integer id;
#JacksonXmlProperty(localName = "kod-produktu")
private Item product;
#JacksonXmlProperty(localName = "spravce")
private Item administrator;
#JacksonXmlElementWrapper(localName = "ziskatele")
#JacksonXmlProperty(localName = "xml-ziskatel")
private List<Customer> customers;
#JacksonXmlProperty(localName = "frekvence")
private Item frequency;
#JacksonXmlProperty(localName = "datum-sjednani")
private Item createdAt;
#JacksonXmlProperty(localName = "pocatek")
private Item startDate;
#JacksonXmlProperty(localName = "konec")
private Item endDate;
#JacksonXmlElementWrapper(localName = "objekty-unik-id")
#JacksonXmlProperty(localName = "int")
private List<Integer> vehicle;
#JacksonXmlProperty(localName = "xml-hodnota")
#JacksonXmlElementWrapper(localName = "udaje")
private List<Item> values;
#JacksonXmlProperty(localName = "xml-objekt")
#JacksonXmlElementWrapper(localName = "objekty-all")
private List<ObjectItem> objects;
#JacksonXmlElementWrapper(localName = "adresy")
#JacksonXmlProperty(localName = "xml-adresa")
private List<AddressItem> address;
//getters setters contructors stuff
}
Use the Java field names, instead of the XML element names.
For example, using a simplified version of your ContractDetail class:
Using this:
#JsonPropertyOrder({"id", "vehicle", "zpplID"})
Generates this:
<xmlroot>
<cnt-unik-id>123</cnt-unik-id>
<objekty-unik-id>
<int>678</int>
<int>789</int>
</objekty-unik-id>
<zpplID>456</zpplID>
</xmlroot>
And using this:
#JsonPropertyOrder({"vehicle", "zpplID", "id"})
Generates this:
<xmlroot>
<objekty-unik-id>
<int>678</int>
<int>789</int>
</objekty-unik-id>
<zpplID>456</zpplID>
<cnt-unik-id>123</cnt-unik-id>
</xmlroot>
Soo #andrewjames's answer works but If someone still needs/wants to use xml element names the solution I came up with looks like this:
#JsonPropertyOrder({"cnt-unik-id","kod-produktu","frekvence","datum-sjednani",
"pocatek","konec","spravce","ziskatele","objekty-unik-id","int","udaje","xml-hodnota","objekty-all","xml-objekt","adresy","xml-adresa","zpp"})

Spring Cassandra store a List with custom object's

I like to store a object like:
#Table(value = "my_table")
public class MyTableDto {
#PrimaryKeyColumn(name = "uid", type = PrimaryKeyType.PARTITIONED)
#CassandraType(type = DataType.Name.UUID)
private UUID uid;
#Column(value = "child_ids")
private List<ChildIdDto> childIds;
}
Then I get the exception:
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Only primitive types are allowed inside Collections for property [childIds] of type ['interface java.util.List'] in entity [de.myapplication.repository.dto.MyTableDto]
I do understand the exception, but is there another way to persist custom objects?
EDIT:
When I comment out this attribute, everything works
! Never say never, I got the solution.
To give a good example, I will list all according classes.
ParentClass.java
#Table(value = "my_table") //OPT
public class MyTableDto {
#PrimaryKeyColumn(name = "uid", type = PrimaryKeyType.PARTITIONED)
#CassandraType(type = DataType.Name.UUID)
private UUID uid;
#Column(value = "child_ids") //OPT
private List<ChildDto> childIds;
}
ChildDto.java
#UserDefinedType // THE SOLUTION
public class ChildDto {
#Column(value = "child") //OPT
#CassandraType(type = DataType.Name.TEXT) //OPT
private String groupId;
#Column(value = "description") //OPT
#CassandraType(type = Name.TEXT) //OPT
private String description;
}
The #UserDefinedType is the solution.
For more information see here.
NOTE: Each annotation with "OPT" is NOT required

Jackson: Object Mapper annotations to deserialize a inner collection

I want to convert the following json into a java object, using as much as possible annotations.
{"user":{
"id":1,
"diets":[
{"diet":{
"name":"...",
"meals":[]
}
}
]
}
}
I'm getting trouble with the collection diets. I tried to use #JsonProperty but it doesn't work properly. Is there a special annotation for map inner aggregates?
Diet.java
#JsonRootName(value = "diet")
public class Diet {
#JsonProperty(value="name")
private String name;
#JsonProperty(value="meals")
private List<Meal> meals;
private User user;
// Rest of the class omitted.
}
User.java
#JsonRootName(value = "user")
public class User {
#JsonProperty("id")
private long id;
#JsonProperty("diets")
private List<Diet> diets = new ArrayList<Diet>();
// Rest of the class omitted.
}
Thanks!
The diets object in your json is not a List. Its a List of key-value pair with key "diet" and value a diet object. So you have three options here.
One is to create a wrapper object say DietWrapper and use List of diet wrapper in User like
#JsonRootName(value = "user")
class User {
#JsonProperty(value = "id")
private long id;
#JsonProperty(value = "diets")
private List<DietWrapper> diets;
//Getter & Setters
}
class DietWrapper {
#JsonProperty(value = "diet")
Diet diet;
}
Second option is to keep diest as simple list of maps like List>
#JsonRootName(value = "user")
class User {
#JsonProperty(value = "id")
private long id;
#JsonProperty(value = "diets")
private List<Map<String, Diet>> diets;
//Getter & Setters
}
Third option is to use a custom deserializer which would ignore your diet class.
#JsonRootName(value = "user")
class User {
#JsonProperty(value = "id")
private long id;
#JsonProperty(value = "diets")
#JsonDeserialize(using = DietDeserializer.class)
private List<Diet> diets;
//Getter & Setters
}
class DietDeserializer extends JsonDeserializer<List<Diet>> {
#Override
public List<Diet> deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(jsonParser);
List<Diet> diets = mapper.convertValue(node.findValues("diet"), new TypeReference<List<Diet>>() {});
return diets;
}
}

Categories