I don't want to include nested objects values in json which are null, but I obtain different result. I have class:
#Data
public class HoldsType {
#JsonInclude(JsonInclude.Include.NON_NULL)
protected HoldTypeIndicatorType holdTypeIndicator;
#JsonInclude(JsonInclude.Include.NON_NULL)
protected HoldReasonsType holdReasons;
}
And it contains nested HoldTypeIndicatorType class:
#Data
public class HoldTypeIndicatorType {
#JsonInclude(JsonInclude.Include.NON_NULL)
protected Boolean dealerAssignment;
#JsonInclude(JsonInclude.Include.NON_NULL)
protected Boolean someSpecification;
}
I added there #JsonInclude(JsonInclude.Include.NON_NULL) annotations to exclude those fields from results json, but I receive:
{
"holdTypeIndicator": {}
}
I tried also adding
NON_DEFAULT property, or
NON_ABSETNT property,
but it's the same.
The problem is here I have tons of fields type: Boolean.
What should be the simplest way to add this behavior to ObjectMapper to not include this holdTypeIndicator object, when all Boolean nested values are null, in json?
Writing custom Serializable will require adding annotation to all of those fields. Is there any way I can override ObjectMapper default serializer for this?
Related
I have a class:
#EqualsAndHashCode(callSuper = true)
#Data
public class AppealTemplateDto extends AbstractDto {
private List<AbstractFieldDto> fields;
}
This class contains list of AbstractFieldDto inheritors, e.g.:
#EqualsAndHashCode(callSuper = true)
#Data
#NoArgsConstructor
public class InputFieldDto extends AbstractFieldDto {
private String fieldType = FieldType.INPUT.name();
private String text;
}
Totally, there are near 6-7 inheritors, & AbstractTemplateDto may contain any set of them.
Controller:
#PostMapping
public ResponseEntity<AppealTemplateDto> create(#RequestBody AppealTemplateDto dto) {
return ResponseEntity.ok(service.save(dto));
}
When Jackson trying to parse AppealTemplateDto, it crashes with exception:
Caused by:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot
construct instance of
ru.appeal.template.dto.field.AbstractFieldDto
(no Creators, like default construct, exist): abstract types either
need to be mapped to concrete types, have custom deserializer, or
contain additional type information
As I understand, Jackson can't define, how to cast incoming AbstractFieldDto. Please, advice me, what to do?
The Annotation your are needing are:
#JsonTypeInfo
#JsonSubType
#JsonTypeName
Some explanation: if you have many implementation of your abstract type, Jackson can't guess which type is your json, you need to add a type name in json, for example as a new property (this is one of the strategies):
//tell to jackson where to find the type name
#JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = As.PROPERTY, property = "type")
// tell to jackson the implementations to scan
#JsonSubTypes({
#JsonSubTypes.Type(value = InputFieldDto.class, name = "input")
//, ...
})
public class AbstractFieldDto {
}
//tell to jackson what is the type name in json
#JsonTypeName("input")
public class InputFieldDto extends AbstractFieldDto {
private String fieldType = FieldType.INPUT.name();
private String text;
}
I'm trying to retrieve an enum from a database and Hibernate doesn't find the property value and therefore throws the following Exception java.lang.IllegalArgumentException: No enum constant com.intrawa.qx.validator.models.entity.Group.CONFIGTAB.false
The problem occurs when hibernate calls the valueof method of the enum: at java.lang.Enum.valueOf(Enum.java:238)
I'm working with a Database where I cannot change it's column names.
For example look at the code:
#Entity
#Data
#Table(name = "bm_host_groups")
public class Group {
#Enumerated(EnumType.STRING)
private CONFIGTAB configTab;
#AllArgsConstructor
private enum CONFIGTAB {
TRUE("true"),
FALSE("false");
#Getter #Setter
private String value;
}
}
The DB has a column called configTab with enum value type and two possible values ("true", "false"), when hibernate call valueof("true") it doesn't find TRUE and throws the exception.
One solution I found it's on this post: What is the reason for java.lang.IllegalArgumentException: No enum const class even though iterating through values() works just fine?
However, it needs a custom method that takes for example "true" as argument from the DB then capitallize it in order to find the value of the enum.
I searched a way to override Enum's valueof() but this post says it's not possible and basically suggest the same as the first solution, make a custom method and make the client calls it. Post: Override valueof() and toString() in Java enum
Is there a way to make hibernate call a custom method instead of valueof()?
It is not possible to override valueOf(). But it is possible to manipulate the value that valueOf() will get. Namely, the correct solution is to use AttributConverter and discard the #Enumerated annotation, like:
#Getter #Setter
//#Enumerated(EnumType.STRING)
#Convert(converter=ConfigTabConverter.class)
private CONFIGTAB configTab;
Converter is quite simple:
#Converter(autoApply=true)
public class ConfigTabConverter
implements AttributeConverter<CONFIGTAB,, String> {
#Override
public String convertToDatabaseColumn(CONFIGTAB attribute) {
return attribute.getValue();
}
#Override
public CONFIGTAB convertToEntityAttribute(String dbData) {
return CONFIGTAB.valueOf(dbData.toUpperCase());
}
}
I am working on conversion from JSON using Jackson 2, I work with application code that I cannot interfere into (Tacton Software). In there I have a class like that:
public class Quotation {
private Reference currency; // This type does not have deafult constructor
private List<QuotationItem> quotationItems = new ArrayList(); // In this there are abstract fields
// Getters, setters and other fields omitted for clarity
}
So basically I tried already to extend Quotation class like that:
class JSONQuotation extends Quotation{
#JsonSetter("currency")
public void notSetCurrency(JSONReference ref){
this.setCurrency(null);
}
#JsonSetter("items")
#Override
public void setItems (List<QuotationItem> item){
}
}
So there are two types of annotation I used:
Ignore setter for field I don't want to deserialize
Override setter
Anyway I'm still getting errors from ObjectMapper, of course, I had set MixIns
mapper.addMixIn(Quotation.class,JSONQuotation.class);
Anybody can help me with this or recommend some other deserializer ?
By no means am I a Jackon/JSON wizard, which is probably evident from the following issue I'm running into:
I have 2 possible data structures I'm receiving.
The first one is called amountTransaction:
{
"amountTransaction": {
"clientCorrelator":"54321",
"endUserId":"tel:+16309700001"
}
}
Which is represented by the following Java object:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
#JsonTypeName(value = "amountTransaction")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class AmountTransaction {
private String clientCorrelator;
private String endUserId;
...
}
However the amountTransaction object also appears as child element of the paymentTransactionNotification object:
{
"paymentTransactionNotification": {
"amountTransaction": {
"clientCorrelator": "54321",
"endUserId": "tel:+16309700001"
}
}
}
..which I thought would be represented by:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
#JsonTypeName(value = "paymentTransactionNotification")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class PaymentTransactionNotification {
private AmountTransaction amountTransaction;
...
}
Parsing the JSON with the amountTransaction object alone works fine. It's a pretty straightforward example of a WRAPPER_OBJECT.
However when trying to parse the JSON for the paymentTransactionNotification, I'm getting an exception indicating that it can't properly deal with the amountTransaction as element of the paymentTransactionNotification:
com.fasterxml.jackson.databind.JsonMappingException: Could not resolve type id 'clientCorrelator' into a subtype of [simple type, class com.sf.oneapi.pojos.AmountTransaction]
Any thoughts on how I can properly annotate this so my code can properly deal with both stand alone, as well as encapsulated amountTransaction objects?
By default wrapping root node in Jackson is disabled. You can wrap inner objects but if you want to wrap root node you need to enable jackson feature for it (https://jira.codehaus.org/browse/JACKSON-747):
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(SerializationConfig.Feature.WRAP_ROOT_VALUE);
objectMapper.enable(DeserializationConfig.Feature.UNWRAP_ROOT_VALUE);
When you enabled these features you already said Jackson to wrap the root element and you don't need #JsonTypeInfo and #JsonTypeName anymore. You can simple delete them. But now you need to customize the root node name and you can use #JsonRootName for it. Your classes should look like this:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonRootName("amountTransaction")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class AmountTransaction {
private String clientCorrelator;
private String endUserId;
...............
}
And
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonRootName("paymentTransactionNotification")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class PaymentTransactionNotification {
private AmountTransaction amountTransaction;
.............
}
I've tried and Jackson converted both JSON requests as expected.
It seems to be a straightforward implementation but somehow not working for me.
public class ParentEntity {
private List<ChildEntity> childFields;
public List<ChildEntity> getChildFields() {
return childFields;
}
public void setChildFields(List<ChildEntity> childFields) {
this.childFields = childFields;
}
}
Input JSON
{
"childFields": [
{<different child properties>},
{<different child properties>}
]
}
Exception
class ChildEntity not marked as ignorable (11 known properties:...different child field properties
Regarding the exception message that you added, you have a mismatch in the properties you specified in your JSON for the ChildEntity and the ChildEntity properties.
If you have a mismatch and you want to specify more properties in JSON, than available in the ChildEntity class, you can use Jackson's
#JsonIgnoreProperties
annotation. It will ignore every property you haven't defined in your POJO.
You could also choose to use:
ObjectMapper objectMapper = getObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
It will ignore all the properties that are not declared.