I have one model class which has approximately 100 property fields. I need to change the jsonProperty name's for one usage scenario but in all other cases where i'm using this class the property name should not be change. What would be the ideal way to handle this situation.
List<DebitTable> debitTableList = getListData();
Below is the DebitTable class.
#Validated
#Data
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#Builder
public class DebitTable {
#JsonProperty("debitId")
private Long debitId;
#JsonProperty("debitName")
#Pattern(regexp = "^[a-zA-Z0-9 ]*$")
#Size(max = 10)
private String debitName;
.....
}
In one of the usage which returns this List<DebitTable> , i want to change the jsonProperty name from debitId to "Debit Id" and "debitName" to "Debit Name"...Do i need to create another model class by changing the jsonProperty name,but that would be very difficult to set each and every field from one model DebitTable class to other new model class.
Related
Is there any annotation to let us get another value if original value is null?
#Getter
#NoArgsConstructor
#AllArgsConstructor
#ToString
public class SomeDto extends BaseDto {
private BigDecimal a;
#GetOrAlternative(alternative = "a")
private BigDecimal b;
For example, I want to get value a if b is null on above code.
I want to use that like dto.getBOrAlternative().
Is that possible?
If that is not possible, how can I implement that?
I tried to make custom annotation and processor following this: https://www.happykoo.net/#happykoo/posts/256
However, it didn't work. I think it is because that is not a field level.
I'm extending code from an existing Java class that serializes to and from XML. The existing class is somewhat like this:
#Getter
#JacksonXmlRootElement("element")
public class Element {
#JacksonXmlProperty(localName = "type", isAttribute = true)
private String type;
}
The type field has a finite set of possible values so I created an enum Type with all possible values and (to avoid breaking existing functionality) added a new field to the class, like so:
#Getter
#JacksonXmlRootElement("element")
public class Element {
#JacksonXmlProperty(localName = "type", isAttribute = true)
private String type;
#JacksonXmlProperty(localName = "type", isAttribute = true)
#JsonDeserialize(using = TypeDeserializer.class)
private Type typeEnum;
}
This gives me the following error:
Multiple fields representing property "type": Element#type vs Element#typeEnum
I understand why this is a problem cuz when Jackson would try to serialize the class, two fields in my class map onto the same field in the output XML.
I tried adding a #JsonIgnore on one of the fields and it gets rid of the error but has the side effect of not populating the ignored field either. Is there a way to annotate that a field should be deserialized (while reading XML) but not serialized (while writing XML)?
I really need to keep both fields in the class to not disturb any legacy code that might be using the first field, but at the same time allow newer code to leverage the second field.
Thank you!
We have a model like:
#JsonPropertyOrder({
"id",
"alpha2_code",
"alpha3_code",
"name"
})
#Getter
#Setter
public class Country {
private Long id;
private String alpha2Code;
private String alpha3Code;
private String name;
}
and a ObjectMapper instance like:
var jsonMapper = new ObjectMapper();
jsonMapper.enable(SerializationFeature.INDENT_OUTPUT);
jsonMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
jsonMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
jsonMapper.registerModule(new JavaTimeModule());
to create the following JSON:
{
"id": 1,
"alpha2_code": "NL",
"alpha3_code": "NLD",
"name": "Netherlands",
}
This works all as expected.
What important to mention is that we are using #JsonPropertyOrder to sort the output.
This annotation requires the field names as how they are in the output; thus SNAKE CASE like "alpha2_code" and not "alpha2Code" as the Java property name.
Now we have a requirement to create YAML as out put as well (based on the same model).
But the naming convention for the YAML output needs to be KEBAB CASE.
Is there a smart way to solve this?
What I'm thinking of is to move the #JsonPropertyOrder to mix-ins and to introduce CountrySnakeMixin and CountryKebabMixin mix-in classes and use these in separate object mappers.
For this simple example it seems quite straightforward but with a model of 50 - 100 classes this becomes a maintenance nightmare.
I tested
This annotation requires the field names as how they are in the
output
as not correct:
#JsonPropertyOrder({
"id",
"alpha2Code",
"alpha3Code",
"name"
})
works as intended, also changing the order, both in snake and kebab case.
The hibernate entities have the fields named in camel case, but when a DTO constructed from that entity is returned from a REST API we convert the field name to snake case.
There is a generic way to convert every DTO field into snake case with a jackson configuration like so
spring.jackson.property-naming-strategy: SNAKE_CASE
The issue with this is now for example, with Spring paging and sorting if we want to sort by parameter we need to pass the parameter as camel case and not as snake case.
Example:
Entity looks like this:
#Data
#Entity
#Table
public class Entity {
#Id
#Column(name = "id", updatable = false, nullable = false)
#GeneratedValue(generator = "uuid")
#Access(AccessType.PROPERTY)
private UUID id;
#Column(name = "some_text")
private String someText;
}
DTO looks like this:
#Data
public class EntityDTO implements Serializable {
private UUID id;
private String someText;
}
The output JSON is the following:
{
"id": "80fb034a-36c1-4534-a39f-b344fa815a2d",
"some_text": "random text"
}
Now if we would like to call the endpoint with a sort parameter for example:
/entities?sort=some_text&some_text.dir=desc
it will not work because the field in the entity is actually someText and not some_text which is quite confusing because the output is in snake case and not camel case.
So the general question is how to deal with this? Is there a smart way to do it? Some jackson configuration or argument handler configuration? Or do I need to manually convert every single snake case parameter to camel case?
Thank you guys in advance.
you the below property in application.properties file to convert Snake case to camel case.
spring.jackson.property-naming-strategy=SNAKE_CASE
Or you can annotate the attributes as below in case you map only a single class.
#JsonProperty("some_text")
private String someText;
OR annotate the entity as below
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
Below I provide the solution which would solve your problem without the need for definition of mapping for each DTO field name to its corresponding DAO/entity field name. It's using constants and method of com.google.common.base.CaseFormat class from Google Guava library for transformation of strings in one case to another. I assume that you are extracting paging and ordering info from request in instance of org.springframework.data.domain.Pageable class.
public Page<Entity> getEntities(Pageable dtoPageable) {
PageRequest daoPageable = PageRequest.of(
dtoPageable.getPageNumber(),
dtoPageable.getPageSize(),
convertDtoSortToDaoSort(dtoPageable.getSort())
);
return entityRepository.findAll(daoPageable);
}
private Sort convertDtoSortToDaoSort(Sort dtoSort) {
return Sort.by(dtoSort.get()
.map(sortOrder -> sortOrder.withProperty(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, sortOrder.getProperty())))
.collect(Collectors.toList())
);
}
I have two classes TableNameA and TableNameB inside two different dependencies DependencyA and DependencyB representing tables table_name_a and table_name_b with fields described below.
TableName: table_name_a
Field's Name: field_name_p, field_name_q, field.
TableName: table_name_b
Field's Name: field_name_r, field_name_s.
#Entity
#Table(name = "table_name_a")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class TableNameA{
#Id
private int field;
private int fieldNameP;
private int fieldNameQ;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
public class TableNameB{
#Column(name = "field_name_r")
private int fieldNameR;
#Column(name = "field_name_s")
private int fieldNameS;
}
log.info(dslContext.selectFrom(TableNameA.TABLE_NAME_A)
.limit(4)
.fetch()
.into(dependencyA.TableNameA.class).toString());
log.info(dslContext.selectFrom(TableNameB.TABLE_NAME_B)
.limit(4)
.fetch()
.into(dependencyB.TableNameB.class).toString());
I am using jooq as explained above and I want to map table_name_a and table_name_b record into TableNameA and TableNameB class but in the object of TableNameA only 'field' member variable is mapped properly and rest of member variable's fieldNameP, fieldNameP are mapped to null rather than corresponding values in column of table and TableNameB is mapped properly.
The issue here is member variable's fieldNameP, fieldNameP are mapped to null rather than corresponding values in column of table
And One more condition i can't edit TableNameA and TableNameB classes instead I have to write my own models to map if i don't get solution for this.
What you describe is a known issue in jOOQ: https://github.com/jOOQ/jOOQ/issues/4586. Also the fields without a #Column annotation should be mapped, unless they are annotated as #Transient. The reason field gets mapped properly is that it has an #Id annotation.
For the time being I suggest you vote for the linked GitHub issue so that the issue gets attention and can be properly prioritized.