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
Related
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?
I want to serialize a JSON-String I receive as a POJO, for further usage in my code, but I am struggling to get it working without writing a custom serializer.
I would prefer as solution without writing a custom serializer, but if that is the only possible way I will write one.
Additionally I believe the data I receive is a weird JSON since the list I request is not sent as list using [] but rather as a object using {}.
I receive the following list/object (shortened):
{
"results": {
"ALL": {
"currencyName": "Albanian Lek",
"currencySymbol": "Lek",
"id": "ALL"
},
"XCD": {
"currencyName": "East Caribbean Dollar",
"currencySymbol": "$",
"id": "XCD"
},
"EUR": {
"currencyName": "Euro",
"currencySymbol": "â?¬",
"id": "EUR"
},
"BBD": {
"currencyName": "Barbadian Dollar",
"currencySymbol": "$",
"id": "BBD"
},
"BTN": {
"currencyName": "Bhutanese Ngultrum",
"id": "BTN"
},
"BND": {
"currencyName": "Brunei Dollar",
"currencySymbol": "$",
"id": "BND"
}
}
}
I created my first POJO for the inner object like this:
public class CurrencyDTO implements Serializable {
private String currencyName;
private String currencySymbol;
private String currencyId;
#JsonCreator
public CurrencyDTO( #JsonProperty( "currencyName" ) String currencyName, #JsonProperty( "currencySymbol" ) String currencySymbol,
#JsonProperty( "id" ) String currencyId )
{
this.currencyId = currencyId;
this.currencyName = currencyName;
this.currencySymbol = currencySymbol;
}
}
which itself is fine. Now I wrote another POJO as a wrapper for the data a layer above which looks like this:
public class CurrencyListDTO implements Serializable {
private List<Map<String, CurrencyDTO>> results;
public CurrencyListDTO()
{
}
}
Adding the annotations #JsonAnySetter or using the #JsonCreator didn't help either, so I removed them again and now I am wondering which little trick could enable the correct serialization of the json.
My Exception is the following:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
at [Source: (String)"{"results":{"ALL":{"currencyName":"Albanian Lek","currencySymbol":"Lek","id":"ALL"},"XCD":{"currencyName":"East Caribbean Dollar","currencySymbol":"$","id":"XCD"},"EUR":{"currencyName":"Euro","currencySymbol":"â?¬","id":"EUR"},"BBD":{"currencyName":"Barbadian Dollar","currencySymbol":"$","id":"BBD"},"BTN":{"currencyName":"Bhutanese Ngultrum","id":"BTN"},"BND":{"currencyName":"Brunei Dollar","currencySymbol":"$","id":"BND"},"XAF":{"currencyName":"Central African CFA Franc","id":"XAF"},"CUP":{"cur"[truncated 10515 chars]; line: 1, column: 12] (through reference chain: com.nico.Banking.api.data.dto.CurrencyListDTO["results"])
You should change your CurrencyListDTO to:
public class CurrencyListDTO {
private Map<String, CurrencyDTO> results;
// getters and setters
}
Because the results field in the response object is another object with the currencyId as key and no array.
You then can create your list of currencies like this:
ObjectMapper mapper = new ObjectMapper();
CurrencyListDTO result = mapper.readValue(json, CurrencyListDTO.class);
List<CurrencyDTO> currencies = new ArrayList<>(result.getResults().values());
Your CurrencyListDTO should look like below. results property is a JSON Object which should be mapped directly to Map. You can convert it to Collection using keySet or values methods.
class CurrencyListDTO implements Serializable {
private Map<String, CurrencyDTO> results;
public Map<String, CurrencyDTO> getResults() {
return results;
}
public void setResults(Map<String, CurrencyDTO> results) {
this.results = results;
}
#Override
public String toString() {
return "CurrencyListDTO{" +
"results=" + results +
'}';
}
}
I have been looking solution for this problem but could not find one so asking this question.
I have some data which looks like this
{
"data": [
{
"id": "5ab892c71810e201e81b9d39",
"isSignedUpUsingFb": false,
"personalInformation": {
"firstName": "jio",
"lastName": "g",
"mobileNumber": "1234567890",
},
"accountBalance": 0,
}
]
},
I want to write a java code to change the data structure to this
{
"data": [
{
"id": "5ab892c71810e201e81b9d39",
"isSignedUpUsingFb": false,
"personalInformation_firstName":"jio",
"personalInformation_lastNAme":"g",
"personalInformation_mobileNumber":"1234567890",
"accountBalance": 0,
}
]
},
I am getting data from db as:
#Override
public List<User> getAllUsers() {
logger.debug("entering all users method");
List<User> allUsers=mongoOperations.findAll(User.class);
for (User user : allUsers) {
PersonalInformation info=user.getPersonalInformation());
//manipulation code here
user.setPersonalInformation(info);
}
return allUsers;
}
So I want to write a logic so that i can convert the data in desired format and send it a return type. I know how to do same thing using J query but I want to do it in backend so any code for the above or any link will help.
I have fond one solution which is very simple.So, basically when we create object for nested data we create it like this in JAVA.
public MyClass{
public String name;
public String contact;
public PersonalInformation personalinformation;
//setters and getter here
}
this will give me data as
"MyClass":{
"name": "abc",
"contact": "12345",
"personalInformation":{
"address": "asdasdasdad",
"city":"asdadad",
"pin": "asdfg",
}
}
so to remove this nested data we need to use #JsonUnwrapped which removes all the nested object and add it to our main object.
public MyClass{
public String name;
public String contact;
#JsonUnwrapped
public PersonalInformation personalinformation;
//setters and getter here
}
which will change the data structure as:
"MyClass":{
"name": "abc",
"contact": "12345",
"address": "asdasdasdad",
"city":"asdadad",
"pin": "asdfg",
}
for more reference you can check this link http://fasterxml.github.io/jackson-annotations/javadoc/2.0.0/com/fasterxml/jackson/annotation/JsonUnwrapped.html
Hope this helps.
There are multiple possible solutions. As Prabhav has mentioned the most intuitive one would be to create a new class and from there a object which can be transformed with a library to a JSON.
Variant one:
The new class would look like your data structure you want and access would be:
PersonalInformationJson pf = new PersonalInformationJson();
pf.setFirstName = info.getPersonalInformation_firstName
//... setting the rest of the object
//using jackson
ObjectMapper mapper = new ObjectMapper();
try {
// convert user object to json string and return it
String jsonString = mapper.writeValueAsString(u);
}
The other easier version to create a string, either per hand or use a lib:
// using org.json.JSONObject
String jsonString = new JSONObject().put("personalInformation_firstName", info.value())
.put("personalInformation_lastNAme", info.value());
Similar question might be asked before on here, but I had no luck and I was wondering how to extract specific objects like user in from below json string and then construct an ArrayList. However, there is one twist, one of the property directly under Users is a random number, which can be anything!!!
Here is how my json string looks like:
<code>{
"_links": {
},
"count": {
},
"users": {
"123321": { //*Is a random number which can be any number
"_links": {
},
"user": {
"id": "123321",
"name": "...",
"age": "...",
"address": ""
..
}
},
"456654": {
"_links": {
},
"user": {
"id": "456654",
"name": "...",
"age": "...",
"address": ""
...
}
}
...
},
"page": {
}
}
</code>
The java object I would like to transform it to is:
#JsonIgnoreProperties(ignoreUnknown = true) // Ignore any properties not bound here
public class User {
private String id;
private String name;
//setter:getter
}
Note: The transformation should only consider those two fields (id,name), and ignore the rest of the fields from the json response user:{} object.
Ideally, I would like to end up with a list like this:
List<User> users = resulted json transformation should return a list of users!!
Any idea how can I do this please ideally with Jackson JSON Parser/ or maybe GSON?
Since the user keys are random, you obviously can't map them to a named Java field. Instead, you can parse the top-level object as a map and the manually pull out the user objects.
public class UserWrapper {
private User user;
public User getUser() { return user; }
}
public class Root {
private Map<String, UserWrapper> users;
public List<User> getUsers() {
List<User> usersList = new ArrayList();
for (String key : map.keySet()) {
UserWrapper wrapper = map.get(key);
usersList.add(wrapper.getUser());
}
return userList;
}
}
Root root = parseJson();
List<User> users = root.getUsers()
Hope that helps!
jolt transformer is your friend. Use shift with wildcard * to capture arbitrary node value and then standard mappers (Jackson /gson) .
I'm trying to parse the filter parameters sent by a KendoUI grid to my web service and am having some issues convincing Jackson to parse this JSON. As far as I know, I can control the format of the parameters that Kendo sends, but I do not know how I would marshal the parameters into a better format so they remain unchangeable for now.
I intend to convert these parameters into a SQL query for an Oracle database.
Example JSON:
{
"filters":
[
{
"field": "Name",
"operator": "contains",
"value": "John"
},
{
"filters": [
{
"field": "Age",
"operator": "gt",
"value": 20
},
{
"field": "Age",
"operator": "lt",
"value": 85
}
],
"logic", "and"
},
{
"field": "Address",
"operator": "doesnotcontain",
"value": "street"
}
],
"logic": "or"
}
Filters. Java
public class Filters {
private List<Filter> filters;
private String logic;
// accessors/mutators/toString
}
Filter.java
public class Filter {
private String field;
private String operator;
private String value;
// accessors/mutators/toString
}
Unit Test
public class KendoGridFilterTest {
private ObjectMapper mapper;
#Before
public void before() {
mapper = new ObjectMapper();
}
#Test
public void jsonParseTest() {
final String json = "{\"filters\":[{\"field\":\"Name\",\"operator\":\"contains\",\"value\":\"John\"},{filters: [{\"field\":\"Age\",\"operator\": \"eq\",\"value\": 85},{\"field\": \"Age\",\"operator\": \"eq\",\"value\": 85}]\"logic\", \"and\",},{\"field\": \"Address\",\"operator\": \"doesnotcontain\",\"value\": \"street\"}],\"logic\":\"or\"}";
Filters filters = mapper.readValue(json, Filters.class);
assertTrue(json.equals(filters.writeValueAsString(filters);
}
}
Errors
com.fasterxml.jackson.databind.UnrecognizedPropertyException: Unrecognized field
'logic'(com.example.Filter) not market as ignorable (3 known properties
"value", "field", "operator")
at [Source: java.io.StringReader#3bb2b8; line: 1, column 76] (through reference
chain: com.example.Filters["filters"]->com.example.Filter["logic"]
I've also tried adding #JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#id") to the Filters class and get the same errors.
your Filter class is not correct. It should extend Filters.
After correcting your unit test (json is incorrect) it can load your json into a Filters Object.
public class Filter extends Filters {
private String field;
private String operator;
private String value;
// accessors/mutators/toString
}