I need to create the model class for the following type of json:
{
"AdditinalInfo": [
{
"Tag": "ORDER",
"Value": "[{\"EN_CODE\":\"8901233014951\",\"SKU_CODE\":\"1000003\",\"SKU_DESC\":\"5Star crunchy chocolate 33g\" ,\"QUANTITY\":\"1\",\"UNIT_SELLING_PRICE\":\"18.0\"}]"
}
]
}
Please help how can I create model class for the above json. I need to send the json using the POST method.
use
http://www.jsonschema2pojo.org/
delete json which shows its a dummy copy past json to json place
click Preview and then finally download zip
done.
Thanks
You can generate model from json automatically using online tools like THIS
-----------------------------------com.example.AdditinalInfo.java-----------------------------------
package com.example;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
#Generated("org.jsonschema2pojo")
public class AdditinalInfo {
#SerializedName("Tag")
#Expose
public String tag;
#SerializedName("Value")
#Expose
public String value;
}
-----------------------------------com.example.Example.java-----------------------------------
package com.example;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
#Generated("org.jsonschema2pojo")
public class Example {
#SerializedName("AdditinalInfo")
#Expose
public List<AdditinalInfo> additinalInfo = new ArrayList<AdditinalInfo>();
}
class AdditinalInfo {
public TagValuesPair[] AdditinalInfo;
}
class TagValuesPair {
public String Tag;
public Map<String, String> Value;
}
// getter setter constructors are ommitted for simplicity
You don't need to create model for sending this Json via Retrofit.
#POST("/save")
Call<JsonElement> request(#Body RequestBody requestBody);
String resultJson = ... // your json
//parse it to RequestBody type
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), resultJson);
//create adapter
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl(Constants.ROOT_API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
IConstructSecureAPI service = restAdapter.create(IConstructSecureAPI.class);
Call<JsonElement> result = service.CreateAccount(requestBody);
result.enqueue(new Callback<JsonElement>() {
#Override
public void onResponse(Call<JsonElement> call, retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()){
JsonElement jsonElement = response.body();
JsonObject withResponse = jsonElement.getAsJsonObject();
}
else{
System.out.println(response.message());
}
}
#Override
public void onFailure(Call<JsonElement> call, Throwable t) {
}
});
{} braces are for object and [] are Arrays .
For example,
class ModelClass{
public ArrayList<ADDITIONALINFOCLASS> AdditinalInfo;
public class ADDITIONALINFOCLASS {
public String Tag;
public String Value;
}
}
The error that you are getting is for wrong parsing, try this code and see if it works.
Related
I am serializing a class that includes an unmodifiable list with default typing enabled. The problem is that the type that Jackson uses is
java.util.Collections$UnmodifiableRandomAccessList
which, for some reason, the deserializer does not know how to handle.
Is there a way to tell Jackson to set the type as
java.util.ArrayList
which the deserializer does know how to handle, instead? If possible, I'd like to do it using mixins.
Something like
public abstract class ObjectMixin {
#JsonCreator
public ObjectMixin(
#JsonProperty("id") String id,
#JsonProperty("list") #JsonSerialize(as = ArrayList.class) List<String> list;
) {}
}
which, unfortunately, does not work.
I would like to start from security risk warning which comes from ObjectMapper documentation:
Notes on security: use "default typing" feature (see
enableDefaultTyping()) is a potential security risk, if used with
untrusted content (content generated by untrusted external parties).
If so, you may want to construct a custom TypeResolverBuilder
implementation to limit possible types to instantiate, (using
setDefaultTyping(com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder<?)).
Lets implement custom resolver:
class CollectionsDefaultTypeResolverBuilder extends ObjectMapper.DefaultTypeResolverBuilder {
private final Map<String, String> notValid2ValidIds = new HashMap<>();
public CollectionsDefaultTypeResolverBuilder() {
super(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE);
this._idType = JsonTypeInfo.Id.CLASS;
this._includeAs = JsonTypeInfo.As.PROPERTY;
notValid2ValidIds.put("java.util.Collections$UnmodifiableRandomAccessList", ArrayList.class.getName());
// add more here...
}
#Override
protected TypeIdResolver idResolver(MapperConfig<?> config, JavaType baseType, Collection<NamedType> subtypes,
boolean forSer, boolean forDeser) {
return new ClassNameIdResolver(baseType, config.getTypeFactory()) {
#Override
protected String _idFrom(Object value, Class<?> cls, TypeFactory typeFactory) {
String id = notValid2ValidIds.get(cls.getName());
if (id != null) {
return id;
}
return super._idFrom(value, cls, typeFactory);
}
};
}
}
Now, we can use it as below:
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.jsontype.NamedType;
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver;
import com.fasterxml.jackson.databind.type.TypeFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.setDefaultTyping(new CollectionsDefaultTypeResolverBuilder());
Root root = new Root();
root.setData(Collections.unmodifiableList(Arrays.asList("1", "b")));
String json = mapper.writeValueAsString(root);
System.out.println(json);
System.out.println(mapper.readValue(json, Root.class));
}
}
class Root {
private List<String> data;
public List<String> getData() {
return data;
}
public void setData(List<String> data) {
this.data = data;
}
#Override
public String toString() {
return "Root{" +
"data=" + data +
'}';
}
}
Above code prints:
{
"data" : [ "java.util.ArrayList", [ "1", "b" ] ]
}
Root{data=[1, b]}
You can even map it to List interface:
notValid2ValidIds.put("java.util.Collections$UnmodifiableRandomAccessList", List.class.getName());
And output would be:
{
"data" : [ "java.util.List", [ "1", "b" ] ]
}
I recently work with Commercetools platform and I have such a question. How we can find product or category and so on by incomplete name?
For example if in my url I wrote something like this
https://localhost:8080/cat?catName=G
I wanna find all categories which contains a G . How we can done this?
You can get this with a categoryAutoComplete query on the GraphQL API. The following query asks for categories beginning with "hi". You need to provide two characters at least, with one letter only it doesn't return any result.
{
categoryAutocomplete(locale: "en", text: "hi") {
results {
name(locale: "en")
}
}
}
On my test project it this query returns two categories that have the term "hint" in their English name:
{
"data": {
"categoryAutocomplete": {
"results": [
{
"name": "Test duplicate order hint"
},
{
"name": "order hint test"
}
]
}
}
}
Is this helpful?
You can make a GraphQL request with the commercetools JVM SDK as follows:
First implement the Java class representing your GraphQL response. So if one result object looks like:
{
"name": "category name"
}
Then the implementing java class CategoryAutoCompleteResult would look something like this:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.sphere.sdk.models.Base;
public class CategoryAutoCompleteResult extends Base {
private final String name;
#JsonCreator
public CategoryAutoCompleteResult(#JsonProperty("name") final String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Then implement the GraphQL request class CategoryAutoCompleteRequest. This could be simplified by just implementing the SphereRequest interface from the commercetools JVM SDK as follows:
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import io.sphere.sdk.client.HttpRequestIntent;
import io.sphere.sdk.client.SphereRequest;
import io.sphere.sdk.http.HttpMethod;
import io.sphere.sdk.http.HttpResponse;
import io.sphere.sdk.json.SphereJsonUtils;
import io.sphere.sdk.models.Base;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
public class CategoryAutoCompleteRequest extends Base implements SphereRequest<List<CategoryAutoCompleteResult>> {
private final String queryString;
CategoryAutoCompleteRequest(final String queryString) {
this.queryString = queryString;
}
public static CategoryAutoCompleteRequest of(#Nonnull final String queryString) {
return new CategoryAutoCompleteRequest(queryString);
}
#Nullable
#Override
public List<CategoryAutoCompleteResult> deserialize(final HttpResponse httpResponse) {
final JsonNode rootJsonNode = SphereJsonUtils.parse(httpResponse.getResponseBody());
final JsonNode results = rootJsonNode.get("data").get("categoryAutocomplete").get("results");
return SphereJsonUtils
.readObject(results, new TypeReference<List<CategoryAutoCompleteResult>>() {
});
}
#Override
public HttpRequestIntent httpRequestIntent() {
final String queryBody =
String.format("{categoryAutocomplete(locale: \"en\", text: \"%s\") {results{name(locale: \"en\")}}}",
queryString);
final String graphQlQuery = buildGraphQlQuery(queryBody);
return HttpRequestIntent.of(HttpMethod.POST, "/graphql", graphQlQuery);
}
private static String buildGraphQlQuery(#Nonnull final String queryBody) {
return String.format("{ \"query\": \"%s\"}", queryBody.replace("\"", "\\\""));
}
}
Then the last step would be to execute the actual request. Assuming you already have a setup SphereClient. Executing the request would looks as follows:
final List<CategoryAutoCompleteResult> results = sphereClient
.execute(CategoryAutoCompleteRequest.of("myIncompleteCatName")).toCompletableFuture().join();
I have a rest service by Java and the request that invokes the REST service contains a JSON object.
I found sub_array_1 and sub_array_2 were empty Lists but other class members have their values in receviedObj.
Does #Consumes() cannot parse more than 1 level json object ?
How could I get correct data in sub_array_1 and sub_array_2 ?
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/* ... */
#POST
#Path("")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response sendRequest(ClassB receviedObj) {
/* ... */
}
json object likes:
{
"item_1": "value_1",
"item_2": "value_2",
"item_3": "value_3",
"otherItems": [
{
"subitem_1": "subvalue_1",
"subObject": {
"name": "aaabbb",
"sub_array_1": [
{
"data_1": "d11",
"data_2": "d12",
"data_3": "d13"
},
{
"data_1": "d21",
"data_2": "d22",
"data_3": "d23"
}
],
"sub_array_2": [
{
"tag_1": "v1",
"tag_2": "v2",
"tag_3": "v3",
"tag_4": "v4"
}
]
}
}
]
}
java class:
public class ClassB {
public String item_1;
public String item_2;
public String item_3;
public List<otherItems> otherItems;
}
public class otherItems{
public String subitem_1;
public subObject subObject;
public otherItems(){
this.subitem_1 = "";
this.subObject = new subObject();
}
// ================================
public static class subObject{
public String name;
public List<sub_array_1> sub_array_1;
public List<sub_array_2> sub_array_2;
public subObject(){
this.name= "";
this.sub_array_1 = new ArrayList<sub_array_1>();
this.sub_array_2 = new ArrayList<sub_array_2>();
}
}
// =========================================
public static class sub_array_1 {
public String data_1;
public String data_2;
public String data_3;
public String getdata_1() {
return data_1;
}
public String getdata_2() {
return data_2;
}
public String getdata_3() {
return data_3;
}
}
public static class sub_array_2 {
public String tag_1;
public String tag_2;
public String tag_3;
public String tag_4;
public String gettag_1() {
return tag_1;
}
public String gettag_2() {
return tag_1;
}
public String gettag_3() {
return tag_1;
}
public String gettag_4() {
return tag_1;
}
}
}
I do not think the JSON you are sending is appropriate for ClassA as it has some params which are not there in ClassA. Params like item_1, item_2 etc. Per my test, following JSON should populate ClassA fine.
{
"subitem_1": "subvalue_1",
"subObject": {
"name": "aaabbb",
"sub_array_1": [
{
"data_1": "d11",
"data_2": "d12",
"data_3": "d13"
},
{
"data_1": "d21",
"data_2": "d22",
"data_3": "d23"
}
],
"sub_array_2": [
{
"tag_1": "v1",
"tag_2": "v1",
"tag_3": "v1",
"tag_4": "v1"
}
]
}
}
So, either you need to change ClassA to incorporate other fields or you need to use above JSON. Also, I suggest some reading on coding practices and naming conventions for Java
Finally I still cannot figure out why JSX-RS cannot convert JSON to java class correctly.
I use Gson to do the conversion and get the object with correct data.
I use Retrofit and GSON and I'm getting Json like this:
{
"firstName": "John",
"lastName": "Doe",
"passporRf": {
"number": "996633",
"series": "1111",
"code": "66666"
}
}
And when user doenst have a passport - this fields is boolean with "false" value.
How to deserialize it correctly and get boolean value - false, when this field is boolean and get JSON object when its object.
I found a JSONDeserializer but i cant to use it correctly. Code is:
public class DocumentDeserializer implements JsonDeserializer<Passport> {
#Override
public Passport deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonPrimitive primitive = json.getAsJsonPrimitive();
if (primitive.isBoolean()) {
// What value do i have to return here?
}
return context.deserialize(json, Passport.class);
}
}
Don't use GSon nor any other binding library. Nothing can be bound to "either a boolean or an object", so don't try.
Use a JSON parser, and look at the JSON content to obtain the information you want. Possibly build a User object out of the information you can find.
Code is given below,
Sample.class
import com.google.gson.Gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
/**
* Class containing news information in form of POJO.
*/
public class Sample {
public String firstName;
public String lastName;
private List<SampleOne> passporRf;
public List<SampleOne> getPassporRf() {
return passporRf;
}
private void setPassporRf(List<SampleOne> passporRf) {
this.passporRf = passporRf;
}
// Using custom DeSerializer for "multimedia" object since the API is just "Great"
public static class SampleDetailsDeSerializer implements JsonDeserializer<Sample> {
#Override
public Sample deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Sample accountState = new Gson().fromJson(json, Sample.class);
JsonObject jsonObject = json.getAsJsonObject();
if (jsonObject.has("passporRf")) {
JsonElement elem = jsonObject.get("passporRf");
if (elem != null && !elem.isJsonNull()) {
if(elem.isJsonPrimitive()){
accountState.setPassporRf(null);
} else {
final List<SampleOne> passporRfList = new Gson().fromJson(elem.getAsJsonArray().toString()
, new TypeToken<List<SampleOne>>(){}.getType());
accountState.setPassporRf(passporRfList);
}
}
}
return accountState ;
}
}
}
SampleOne.class
public class SampleOne {
public String number;
public String series;
public String code;
}
Hope it may help you.
I Can't cast input object to DTO because of below error ExecutionStrategy.resolveField() - Exception while fetching data java.lang.ClassCastException: java.util.LinkedHashMap incompatible with com.fathome.graphql.OffersDto
OffersDto inputObject = environment.getArgument("offersInput");
please let me know what's wrong in below code, thanks in advance.
package com.fathome.graphql;
import graphql.schema.*;
import static graphql.Scalars.*;
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition;
import static graphql.schema.GraphQLInputObjectField.newInputObjectField;
import static graphql.schema.GraphQLInputObjectType.newInputObject;
import static graphql.schema.GraphQLList.list;
import static graphql.schema.GraphQLObjectType.newObject;
public class ManualGraphQLQuerySchema {
public static GraphQLObjectType offersResponse = newObject()
.name("OffersResponse")
.field(newFieldDefinition()
.name("offerName")
.type(GraphQLString))
.field(newFieldDefinition()
.name("offerId")
.type(GraphQLString))
.build();
public static GraphQLInputObjectType offersRequestType = GraphQLInputObjectType.newInputObject()
.name("OffersDto")
.field(newInputObjectField()
.name("offerName")
.type(GraphQLString))
.field(newInputObjectField()
.name("offerId")
.type(GraphQLString))
.build();
public static GraphQLObjectType queryType = newObject()
.name("QueryType")
.field(newFieldDefinition()
.name("offers")
.type(offersResponse)
.argument(GraphQLArgument.newArgument()
.name("offersInput")
.type(offersRequestType))
.dataFetcher(new OffersFetcher()))
.build();
}
package com.fathome.graphql;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"offerName",
"offerId"
})
public class OffersDto {
#JsonProperty("offerName")
private String offerName;
#JsonProperty("offerName")
public String getOfferName() {
return offerName;
}
#JsonProperty("offerName")
public void setOfferName(String offerName) {
this.offerName = offerName;
}
#JsonProperty("offerId")
private String offerId;
#JsonProperty("offerId")
public String getOfferId() {
return offerId;
}
#JsonProperty("offerId")
public void setOfferId(String offerId) {
this.offerId = offerId;
}
}
package com.fathome.graphql;
import graphql.schema.DataFetcher;
import graphql.schema.DataFetchingEnvironment;
public class OffersFetcher implements DataFetcher<OffersDto> {
#Override
public OffersDto get(DataFetchingEnvironment environment) {
//Can't cast input object DTO this is error in below line
//ExecutionStrategy.resolveField() - Exception while fetching data
//java.lang.ClassCastException: java.util.LinkedHashMap incompatible with com.fathome.graphql.OffersDto
OffersDto inputObject = environment.getArgument("offersInput");
//calling service to get offerdetails using inputObject
//for testing not calling service just returning mock object.
OffersDto offersDto = new OffersDto();
offersDto.setOfferName("123");
offersDto.setOfferId("456");
return offersDto;
}
}
In below reference link similar to my code working fine.
Episode episode = environment.getArgument("episode");
ReviewInput review = environment.getArgument("review");
http://graphql-java.readthedocs.io/en/latest/execution.html
The values you get from environment.getArgument(...) will either be scalar values (strings, numbers etc) or a Map in case of an object GraphQL input type (like in your case).
You then need to do the deserialization yourself. Since you're using Jackson, it would look like this:
private final ObjectMapper objectMapper;
...
Object rawInput = environment.getArgument("offersInput");
OffersDto inputObject = objectMapper.convertValue(rawInput, OffersDto.class);
Check out graphql-java-tools for schema-first approach, or graphql-spqr for code-first, both make DataFetchers completely transparent, so no manual steps like above needed.