In my request body, I have a field which takes a string as input but is converted into a java object while deserializing.
public class UserCredentials {
#NotBlank String username;
#NotNull ReferenceString passwordRef;
}
the passwordRef value is taken as string and I used #JsonCreator to convert the string to ReferenceString object.
public class ReferenceString {
private String identifier;
private String type;
#JsonCreator
public ReferenceString(String secretRefConfigString) {
// logic to break the string into two and set the
// identifier and type value
return;
}
The serialization and deserialization work fine. I am having an issue with the swagger documentation, the documentation looks like
"UserCredentials" : {
"type" : "object",
"required" : [ "passwordRef" ],
"properties" : {
"username" : {
"type" : "string"
},
"passwordRef" : {
"$ref" : "#/definitions/ReferenceString"
}
}
}
"ReferenceString" : {
"type" : "object",
"properties" : {
"identifier" : {
"type" : "string"
},
"type" : {
"type" : "string"
}
}
}
Since the API will take a string as input, I want that in the docs the type of passwordRef should be shown as String and not ReferenceString, also I don't want the user to see the internal class ReferenceString.
I read about #ApiModel and #ApiModelProperty. I can use the #ApiModelProperty on my fields and the documentation will show that field as a string, but in my code, a lot of fields will be of type ReferenceString and I don't want to use #ApiModelProperty on every field.
Can it be done easily some different way? Can I add some annotation/code only on the ReferenceString to solve this issue?
Related
i have a large json respose:
{
"data" : {
"type" : "gif",
"id" : "BM10Y3Qq3EwK3z8yQd",
"url" : "https://giphy.com/gifs/ramseysolutions-money-gone-BM10Y3Qq3EwK3z8yQd",
"slug" : "ramseysolutions-money-gone-BM10Y3Qq3EwK3z8yQd",
"bitly_gif_url" : "https://gph.is/2mc28WP",
"bitly_url" : "https://gph.is/2mc28WP",
"embed_url" : "https://giphy.com/embed/BM10Y3Qq3EwK3z8yQd",
"username" : "ramseysolutions",
"source" : "",
"title" : "rachel cruze money GIF by Ramsey Solutions",
"rating" : "g",
"content_url" : "",
"source_tld" : "",
"source_post_url" : "",
"is_sticker" : 0,
"import_datetime" : "2018-07-12 12:40:11",
"trending_datetime" : "0000-00-00 00:00:00",
"images" : {
"fixed_width_still" : {
"height" : "113",
"size" : "14977",
"url" : "https://media4.giphy.com/media/BM10Y3Qq3EwK3z8yQd/200w_s.gif?cid=294ee95f49badf517d33e5cd874941ff542e5d2559cf692c&rid=200w_s.gif&ct=g",
"width" : "200"
},
"preview_gif" : {
"height" : "99",
"size" : "48529",
"url" : "https://media4.giphy.com/media/BM10Y3Qq3EwK3z8yQd/giphy-preview.gif?cid=294ee95f49badf517d33e5cd874941ff542e5d2559cf692c&rid=giphy-preview.gif&ct=g",
"width" : "176"
},
...
And I want to get out of there only data -> url and data -> embed_url .
How can this be done correctly?
i try add #JsonProperty to setter :
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
public class GifUrlDto {
private String url;
private String embedUrl;
#JsonProperty("data")
public void setUrl(Map<String, String> data) {
this.url =data.get("url");
this.embedUrl = data.get("embed_url");
}
}
When I try to return it from the function:
#GetMapping("/random")
GifUrlDto getRandomGByExchangeRates();
then i get an error :
Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`)
at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 665] (through reference chain: com.alfa.bank.project.gifAndExchangeRate.dto.GifUrlDto["data"]->java.util.LinkedHashMap["images"])] with root cause
Do I need to make a desiarilizer somehow, or can I do it better?
I want to get out of there only data -> url and data -> embed_url. Do
I need to make a desiarilizer somehow, or can I do it better?
You can do it either without a deserializer or with a deserializer. Without a deserializer you can isolate the part of the json file you are interested and convert it to a JsonNode object using the JsonNode#at method (good if you have to extract properties once in your code):
JsonNode data = mapper.readTree(json).at("/data");
String url = data.get("url").asText(); //<--url is a string
String embedUrl = data.get("embed_url").asText();//<-- embed_url is a string
GifUrlDto dto = new GifUrlDto(url, embedUrl);
You can also write a specific deserializer for the GifUrlDto class reusing the above code (good if you have to deserialize more than one object):
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#JsonDeserialize(using = GifUrlDtoDeserializer.class)//<--added annotation
public class GifUrlDto {
private String url;
private String embedUrl;
}
public class GifUrlDtoDeserializer extends StdDeserializer<GifUrlDto>{
public GifUrlDtoDeserializer() {
super(GifUrlDto.class);
}
#Override
public GifUrlDto deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
final ObjectCodec codec = jp.getCodec();
JsonNode root = codec.readTree(jp);
JsonNode data = root.at("/data");
String url = data.get("url").asText();
String embedUrl = data.get("embed_url").asText();
return new GifUrlDto(url, embedUrl);
}
}
//using the deserializer
GifUrlDto dto = mapper.readValue(json, GifUrlDto.class);
I came across a strange problem today with Deserializing json with explicit null tags.
Below is the sample request and java code.
{
"name": "Jhon"
"address": "Earth"
"department" : [{
"depName": null,
"depId" : "1234"
}]
}
public class Department {
private String depName;
private String depId;
public Department(){
if(this.depName == null){
this.depName = "general";
}
}
}
If I remove the depName from the request the constructor gets called and depName is set as
"general"
If I keep it in the request, the constructor is called but depName is not set.
Why do I see this behavior and what is the solution to this.
I have the following json
{
"id": "1111",
"match": {
"username1": {
"id": "1234",
"name": "alex"
},
"username2": {
"id": "5678",
"name": "munch"
}
}
}
To deserialize it, I have the following data model class.
class json{
String id;
Match match;
}
class Match {
private Map<String,Profile> profiles
}
class Profile{
private String id;
private String name;
}
I am not getting any deserialization error when I am using gson but the
profiles variable is coming as null.
This is how I am deserializing.
var json = gson.fromJson(data,json.class)
inside the match object there can be a dynamic number of usernames not just two . Why am I getting profile object as null and how can I correctly populate it?
Making changes to json is the last resort here. I can make any other required changes.
The issue is your model. You don't need Match because profiles does not really exist in your JSON. You just json (this one with small changes) and Profile:
class json{
String id;
Map<String,Profile> match;
}
This will work.
I have a problem generating a swagger.json file with swagger annotations. The problem is with the generation of map with array.
Ex:
I have an #ApiModel with a field:
#JsonProperty
private Map<String, String[]> example;
When it generates it looks like this:
"example" : {
"type" : "object",
"additionalProperties" : {
"$ref" : "#/definitions/Array"
}
}
"Array" : {
"type" : "object"
},
When I create my client class with swagger-codegen based on the generated json, it resolve to:
private Map<String, Array> example = new HashMap<String, Array>();
But Array doesn`t exist.
Based on what I`ve seen, the json should look like this:
"definitions": {
"example": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}
Is there anyway to make it works ?
I use: Dropwizard, Jersey2, Swagger, JAX-RS
I have two class,
#Document
public class PracticeQuestion {
private int userId;
private List<Question> questions;
// Getters and setters
}
public class Question {
private int questionID;
private String type;
// Getters and setters
}
My JSON doc is like this,
{
"_id" : ObjectId("506d9c0ce4b005cb478c2e97"),
"userId" : 1,
"questions" : [
{
"questionID" : 1,
"type" : "optional"
},
{
"questionID" : 3,
"type" : "mandatory"
}
]
}
How should I write the query method to find PracticeQuestion by userId and questionID using #Query annotation.
Thanks for any suggestion.
If you want to search by userId and QuestionId. You have 2 options.
Use nested queries (Questions in the example above is kind of a nested object and elasticsearch support search on nested objects.). You can read more about it here.
You can create PracticeQuestionRepository with a method findByUserId like shown below.
public interface PracticeQuestionRepository extends ElasticsearchRepository<PracticeQuestion, String> {
#Query("{"query":{"bool":{"must":[{"match":{"userId":"?0"}},{"nested":{"path":"questions","query":{"bool":{"must":[{"match":{"questions.id":"?1"}}]}}}}]}}}")"
Page<PracticeQuestion> findByUserIdAndQuestionId(String userId, String questionId, Pageable pageable);
}
If you do not want to use nested objects. De normalize the schema and flatten the question and userId at the same level and then issue a query on userId and QuestionId.
e.g.
Document 1
{
"_id": "506d9c0ce4b005cb478c2e97",
"userId": 1,
"questionID": 1,
"type": "optional"
}
Document 2
{
"_id": "506d9c0ce4b005cb478c2e97",
"userId": 1,
"questionID": 1,
"type": "optional"
}
Code for Repository
public interface PracticeQuestionRepository extends ElasticsearchRepository<PracticeQuestion, String> {
#Query("{"bool" : {"must" : [ {"field" : {"userId" : "?0"}}, {"field" : {"questionId" : "?1"}} ]}}"")
Page<PracticeQuestion> findByUserIdAndQuestionId(String userId, String questionId, Pageable pageable);
}
Refer this link for more examples