If the field has an annotation, I need to replace all the & characters in the string with § when deserializing, and do the opposite when serializing
For example i created an annotation and marked a field with it
public class SomeData {
#MinecraftColorText
private String str;
}
I need read this json:
{"str":"&6Some nice text"}
and in java object str field need be: §6Some nice text
Im need process only annotated fields, not all String
I wanted to do it with ContextualSerializer, but as I understand it, it replaces the standard serialization
So you should change your custom annotation #MinecraftColorText and add serialize and deserialize convertors:
#JsonDeserialize(converter = MinecraftDeserializeConverter.class)
#JsonSerialize(converter = MinecraftSerializeConverter.class)
#Retention(RUNTIME)
#Target(FIELD)
#JacksonAnnotationsInside
public #interface MinecraftColorText {
}
Deserialize converter:
public class MinecraftDeserializeConverter extends StdConverter<String, String> {
#Override
public String convert(final String s) {
return s.replaceAll("&", "§");
}
}
Serialize converter:
public class MinecraftSerializeConverter extends StdConverter<String, String> {
#Override
public String convert(final String s) {
return s.replaceAll("§", "&");
}
}
and just use:
#MinecraftColorText
private String str;
p.s: Don't forget about #JacksonAnnotationsInside that notify jackson about your custom serialization action.
See more here
Related
I'm trying to convert an enum value into a custom string as part of a JSON response in a Java Spring application. I've attempted to override the enum's toString method and create a Spring converter but both attempts don't seem to work.
Sample Controller
#RequestMapping(value = "/test/endpoint", produces = APPLICATION_JSON_VALUE)
#RestController
public class RecommenderController {
...
#GetMapping("test")
public List<MyEnum> test() {
return new ArrayList<>() {{
this.add(MyEnum.SAMPLE);
}};
}
}
Enum
public enum MyEnum {
SAMPLE("sample"), OTHER_SAMPLE("other sample");
private final String name;
public MyEnum(String name) {
this.name = name;
}
public String toString() {
return this.name;
}
}
This code returns the response ["SAMPLE"] although I want it to return ["sample"]. Is there a way to implement this in Spring?
Assuming you are using the default MappingJackson2HttpMessageConverter, then behind the scenes you are using Jackson's ObjectMapper to perform all the JSON serialization and deserialization. So it's a matter of configuring Jackson for your protocol objects.
In this case, it's probably most straightforward tell Jackson that it can make a single JSON value for your instance of MyEnum with the #JsonValue annotation.
public enum MyEnum {
SAMPLE("sample"), OTHER_SAMPLE("other sample");
private final String name;
public MyEnum(String name) {
this.name = name;
}
#JsonValue
public String getValue() {
return this.name;
}
}
#JsonValue has a bonus, as described in its Javadoc:
NOTE: when use for Java enums, one additional feature is that value returned by annotated method is also considered to be the value to deserialize from, not just JSON String to serialize as. This is possible since set of Enum values is constant and it is possible to define mapping, but can not be done in general for POJO types; as such, this is not used for POJO deserialization.
So if you have the same Enum definition in your application that receives the list, it will deserialize the human readable value back into your Enum.
This can be done by using the #JsonValue annotation in the enum definition:
public enum MyEnum {
...
#JsonValue
public String getName() {
return this.name;
}
}
I have a controller method, that takes in a POJO.
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Dto {
private LocalDate endDate;
private String token;
private TransactionType type;
}
Transaction type is a simple enum, but I want to use a custom conversion from the inbound value to the transaction type.
#Slf4j
#Controller("/api/transactions")
public class IssuerTransactionController {
#Get(value = "/{?tr*}", produces = APPLICATION_JSON)
public List<String> get(Dto tr) {
return new ArrayList<>();
}
}
I have written a converter:
#Slf4j
#Singleton
public class TransactionTypeConverter implements TypeConverter<String, TransactionType> {
#Override
public Optional<TransactionType> convert(String value, Class<TransactionType> targetType, ConversionContext context) {
return Arrays.stream(TransactionType.values())
.filter(txnType -> StringUtils.equals(txnType.getTransactionType(), value) || StringUtils.equals(txnType.name(), value))
.findFirst();
}
}
Micronaut is not using the type converter to transform the inbound value?
Is some special registration process needed in order for Micronaut to know that it should be using the converter?
If I add a constructor to TransactionTypeConverter I can see that the class is never actually created by Micronaut at all.
If I add it as a regular dependency to the controller, it's loaded (no surprise there), but still not used. Is there a step I am missing?
Seems you are using the Binding from Multiple Query values functionality which under the hood is just creating the map of the query parameters you passed in and uses the Jackson to convert the map into your own POJO. So it does not rely on the system converters but only on the Jackson itself.
What you can do is just use Jacksons #JsonCreator annotation to customize the conversation.
Something like this should work.
public enum TransactionType {
A ("A"),
B ("B");
private final String transactionType;
TransactionType(String transactionType){
this.transactionType = transactionType;
}
public String getTransactionType() {
return transactionType;
}
#JsonCreator
public static TransactionType forValue(Collection<String> values) {
if(values == null || values.isEmpty()){
return null;
}
String value = values.get(0);
return Arrays.stream(TransactionType.values())
.filter(txnType -> StringUtils.equals(txnType.getTransactionType(), value) || StringUtils.equals(txnType.name(), value))
.findFirst().orElse(null);
}
}
We have SpringBoot application.
For our pojo's we want to create a custom #ToLowerCase annotation which converts the field variable value to lower case.
Eg:
#Data
Employee {
private String name;
#ToLowerCase
private String emailId;
private String gender;
private String phoneNumber;
}
So my custom #ToLowerCase annotation should convert emailId to lower case.
We want to use this annotation on all kind of Pojos, whether it is rest request pojo or JPA entity pojo.
I have gone through posts on many forums but didn't get any appropriate solution for same.
Is it possible to create such annotation in Spring Boot? If yes then how?
Kindly help
Thanks
Create a custom converter: ToLowerCaseConverter.
public class ToLowerCaseConverter extends StdConverter<String, String> {
#Override
public String convert(String value) {
if (value == null){
return null;
}
return value.toLowerCase();
}
}
After create a new annotation: ToLowerCase. It works for both incoming and outgoing Strings (#JsonDeserialize/#JsonSerialize).
#Retention(RetentionPolicy.RUNTIME)
#JacksonAnnotationsInside
#JsonSerialize(converter = ToLowerCaseConverter.class)
#JsonDeserialize(converter = ToLowerCaseConverter.class)
public #interface ToLowerCase {
}
Finally, your example will work as intended:
#Data
Employee {
#ToLowerCase
private String emailId;
}
I have an annotation and during its runtime use on a method, I want to convert it 9and all its property values) into a JSON object.
The annotation:
public #interface MyAnnotation {
String name();
Integer age();
}
Use of it:
public class MyClass {
#MyAnnotation(name = "test", age = 21)
public String getInfo()
{ ...elided... }
}
When using reflection on an object of type MyClass and getting the annotation from its getInfo method, I would like to be able to convert the annotation to JSON. But it doesn't have any fields (since #interfaces can't have fields), so is there a way to configure an ObjectMapper to use the methods as properties instead?
//This just prints {}
new ObjectMapper().writeValueAsString(method.getAnnotation(MyAnnotation.class));
Found the answer:
Use #JsonGetter and pass it the name of the field you want it to represent.
Example:
public #interface MyAnnotation {
#JsonGetter(value = "name")
String name();
#JsonGetter(value = "age")
Integer age();
}
This will output as the json: {"name":"test","age":21}
I am using genson 1.4 for JSON processing in my REST implementation , JSON Inheritance is not working while using genson .please find the sample code structure below.
This is my BaseObject
This is my BaseObject
public class SynBaseObject implements Serializable
{
private Long status;
//GettersAndSetters
}
This is my Child Class
public class PhoneNumber extends SynBaseObject
{
private String countryCode;
private String areaCode;
private String localNumber;
//GettersAndSetters
}
This is my Response Object
public class ResponseObject implements Serializable
{
private Integer errorCode;
private String errorMessage;
private Long primaryKey;
private SynBaseObject baseClass;
public ResponseObject()
{
}
public SynBaseObject getBaseObject()
{
return baseClass;
}
public void setBaseObject(SynBaseObject baseClass)
{
this.baseClass = baseClass;
}
public Integer getErrorCode()
{
return errorCode;
}
public void setErrorCode(Integer errorCode)
{
this.errorCode = errorCode;
}
}
This is the GENSON JSON Output:
{"baseObject":{"status":null},"errorCode":null,"errorMessage":null,"primaryKey":null}
CountryCode,areaCode and localNumber is missing in JSON,only the base class is processed .Tried the same from code like this
Genson genson = new Genson();
PhoneNumber number = new PhoneNumber();
number.setCountryCode("2");
number.setAreaCode("3");
number.setLocalNumber("9645");
ResponseObject responseObject = new ResponseObject();
responseObject.setBaseObject(number);
String serialize = genson.serialize(responseObject);
System.out.println(serialize);
Output was the same like in the rest service.
By default Genson uses the static type during ser/de. Meaning here it will see the object as an instance of SynBaseObject and not of the concrete type PhoneNumber.
You can tell Genson to use the runtime type via configuration:
Genson genson = new GensonBuilder().useRuntimeType(true).create();
Here you can find some examples on how to customize Genson with Jaxrs.
Note that if you ever want to deserialize to a ResponseObject, then you will probably have troubles as in the json there is no information about what is the concrete type of base object. However if the consumed json is also produced by Genson you can easily solve this problem by enabling class metadata serialization builder.useClassMetadata(true).
Some more documentation about the handling of polymorphic types in Genson.