I'm using Retrofit along with GSON to retrieve data from an API and deserialize it to Java objects using GSON's #SerializedName annotation like below:
public class MyApiObject {
#SerializedName("apiJsonKey")
private String myValue;
...
}
It works fine, but I need to send objects of MyApiObject to a Firebase database and for that the object needs to be serialized back to JSON. Firebase's Java API does this automatically, but it generates the keys based on the instance variable's names (myValue) and not the serialized name ("apiJsonKey").
I know I can use Firebase's #PropertyName annotation, but that would require me to use two annotations with the same values, which is redundant and error-prone.
Is there a better way to do this?
The usual aproach in this cases is to set a constant and use it in both annotations.
public class MyApiObject {
private static final String MY_VALUE_NAME = "apiJsonKey";
#SerializedName(MY_VALUE_NAME)
#ParameterName(MY_VALUE_NAME)
private String myValue;
...
}
This is fairly usual in sequence annotations for JPA.
Related
Hi StackOverflow Community,
I am currently trying to deserialize JSON request bodies provided via Spring Boot #RestController.
The request body contains the following array:
{
...
"productIds": [
"123abc",
"234def"
],
...
}
However, I don't want to deserialize the product IDs into a list of Strings, but rather use a simple wrapper class (for various reasons, including but not limited to additional type safety and validation opportunities). Consequently the class looks like this (Lombok annotations were used to keep the code snippet short):
#Value
#AllArgsConstructor
public class TheRequest {
...
List<ProductId> productIds;
...
}
with ProductId being just a simple wrapper as already said (validation annotations are omitted for the sake of brevity):
#Value
#AllArgsConstructor
public class ProductId{
String id;
}
Looking at Stackoverflow I only found ways to achieve this using rather verbose custom deserialization methods.
However, I am a bit astonished, that Jackson does not provide this functionality out of the box. Consequently it would be great if anyone has any idea if
there is a more elegant way to achieve deserialization of a array of Strings into a List of WrapperObjects, ideally only using Jackson annotations?
there is an elegant way to achieve serialization of such a resulting List of ProductId wrapper objects back into String objects, ideally also using only Jackson annotations? I tried Jacksons #Value but that did not provide the required result.
To me still to verbose but it seems to be a working solution with Jacson 2.14+:
public record PayloadId(String id) {
#JsonCreator(mode = Mode.DELEGATING)
public PayloadId{}
#JsonValue
#Override
public String id() {
return id;
}
}
...and here is the records test https://github.com/FasterXML/jackson-databind/blob/2.14/src/test-jdk14/java/com/fasterxml/jackson/databind/records/RecordCreatorsTest.java
I have an object that in its fields is mandatory that some names have '_' for example local_PC instead of localPC.
The problem I have is that I need it to be local_PC and when a call is made to my app they send that field and I can't change it, but sonar launches me error because it must be localPC
Is there any way I can control it by Jackson?
realizing #jsonproperty only allows me to change the names in the output but not in the input of the controller
#Data
#JsonInclude(JsonInclude.Include.NON_NULL)
#AllArgsConstructor
public class Example{
private String local_PC;
}
Use #JsonAlias
#JsonAlias is introduced in Jackson 2.9 release. #JsonAlias defines one or more alternative names for a property to be accepted during deserialization i.e. setting JSON data to Java object. But at the time of serialization i.e. while getting JSON from Java object, only actual logical property name is used and not alias. #JsonAlias
#JsonAlias({"local_PC", "localPC"})
private String local_PC;
I have a class like this
public class Test {
private String m_username;
public Test() {}
public Test(String username) {
m_username = username;
}
}
And with Moxy. I can post this POJO to other API using Jersey client without any converting operation. But I need to set the m_username as a final field and that will need the empty constructor to initiate m_username. And also the Moxy doesn't work. How can I fix that?
The question isn't very well asked.
AS far as I understand:
You have to make your field final
You have to keep the empty constructor because your object is automatically serialized/deserialized in a format like JSON, using a library such as those you can find in Spring
Unfortunately, these two constraints can't be held at the same time. You will need to abandon final if you want to keep the empty constructor, and conversely.
Is there some way for a Jackson Delegate-based creator to access the raw Json String?
#JsonCreator
private static MyClass createFromJson(Map<String, Object> jsonProperties) {
return new MyClass(rawJson);
}
I am able to get the raw input as a Map of Strings to Objects in the code above, but I want to be able to access the json as a string. I tried the code below (based off of http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html) but that code as written is never invoked.
#JsonCreator
private static MyClass createFromJson(String rawJson) {
return new MyClass(rawJson);
}
Note: This is a spring boot application (1.3.1.RELEASE) that uses Jackson 2.6.4.
Looks like this type of functionality would not make sense in this context. In fact, it appears to me now that requesting the JSON string in this instance defeats the purpose of using jackson in the first place. However if anyone finds themselves here, then the comments from Sotirios Delimanolis may be useful:
"Hack: you can receive a JsonNode as the parameter type and use its toString method to get the corresponding JSON."
"It looks like you want a JsonDeserializer"
So I am just trying out Jersey for REST services and it seems to we working out fine. I only expose get services and all of the object types that I expose with these services have an immutable object representation in Java. By default Jersey seems to use a parser (JAXB?), requiring a #XmlRootElement annotation for the class that should be parsed, zero-arg constructor and setters.
I have been using Gson with no zero-arg constructor, no setters and final on all fields with no problems at all. Is there any way to accomplish this with Jersey(i.e. the paser it is using)? I have seen solutions with adapter classes that map data from a immutable object to a mutable representation, but this seems like a lot of boilerplate(new classes, more annotations, etc.) if it can be achieved with Gson without anything added.
Note: 1) I have heard people promote using zero-arg constructor and claim that Gson should not work without it. This is not what I am interested in. 2) I really have tried googling this but my keywords might be off. In other words, humiliate me in moderation.
EDIT 1:
My webservice works if I do like this:
#XmlRootElement
public class Code{
private String code; //Silly object just used for example.
public Code(){}
//(G || S)etters
}
With this class exposing the object:
#GET
#Produces(MediaType.APPLICATION_JSON)
public Set<Code> get(#QueryParam("name") String name) { // Here I want to use a class of my own instead of String name, haven't figured out how yet.
return this.codeService.get(name);
}
If I replace the Code with the following, the webservice stops working:
public class Code{
private final String code;
#JsonCreator
public Code(#JsonProperty("code") String code) {
this.code = code;
}
//Getters omitted
}
What I want is to be able to 1) have immutable objects that can be parsed to/from json and 2) Be able to define something like #RequestBody in Spring MVC for my incoming objects.
Actually this could be pretty easy with Genson. You just need the jar and then configure the Genson feature to use constructors with arguments (if you don't want to put annotations on it).
Genson genson = new GensonBuilder().useConstructorWithArguments(true).create();
// and then register it with jersey
new ResourceConfig().register(new GensonJaxRSFeature().use(genson));
Or you can use JsonProperty on the arguments. See the User Guide for more details.