Jackson: Parsing an object with an array of objects - java

I'm working on a project where I'm integrating with a 3rd party service that returns a JSON response. I am using Jackson to deserialize the response into a Java POJO. The response is an object that has a few simple fields that Jackson is able to easily parse. However the response also contains an array with a single entry that is also an object. When Jackson attempts to deserialize it I get the top level object containing a list with the single entry in the list, however all of the fields for the single entry in the list are null. Any idea what I'm doing wrong here?
UPDATE: after setting FAIL_ON_UNKNOWN_PROPERTIES to true, I am getting the following stack trace. Still not sure why it is having issues with the wrapped "RecurringDetail" object in the array.
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "RecurringDetail" (class com.adyen.www.models.RecurringDetail), not marked as ignorable (19 known properties: "variant", "contractTypes", "tokenDetails", "aliasType", "name", "creationDate", "firstPspReference", "elv", "card", "additionalData", "shopperName", "socialSecurityNumber", "billingAddress", "bank", "recurringDetailReference", "paymentMethodVariant", "alias", "acquirer", "acquirerAccount"])
at [Source: response.json; line: 5, column: 33] (through reference chain: com.adyen.www.models.RecurringDetailsResult["details"]->java.util.ArrayList[0]->com.adyen.www.models.RecurringDetail["RecurringDetail"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1094)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1470)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1448)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:287)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:259)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:26)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:499)
at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:101)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:276)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2759)
JSON
{
"creationDate": "2017-01-26T23:11:20+01:00",
"details": [
{
"RecurringDetail": {
"acquirer": "TestPmmAcquirer",
"acquirerAccount": "TestPmmAcquirerAccount",
"additionalData": {
"cardBin": "440000"
},
"alias": "B133243153928547",
"aliasType": "Default",
"card": {
"expiryMonth": "8",
"expiryYear": "2018",
"holderName": "Steve HAll",
"number": "0008"
},
"contractTypes": [
"RECURRING"
],
"creationDate": "2017-01-26T23:11:20+01:00",
"firstPspReference": "8524854686798738",
"paymentMethodVariant": "visadebit",
"recurringDetailReference": "8414854686802111",
"variant": "visa"
}
}
],
"invalidOneclickContracts": "false",
"lastKnownShopperEmail": "someones#email.com",
"shopperReference": "xggZcGauSSG5jP+akIlijQ=="
}
Unit Test
public class RecurringDetailResultTest {
public static ObjectMapper mapper = new ObjectMapper()
{
private static final long serialVersionUID = -174113593500315394L;
{
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
configure(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS, true);
setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
};
#Test
public void testParseRecurringDetailResulte() throws IOException {
RecurringDetailsResult result = mapper.readValue(new File("response.json"), new TypeReference<RecurringDetailsResult>(){});
if (result.getDetails() != null && !result.getDetails().isEmpty()) {
RecurringDetail detail = result.getDetails().get(0);
if (StringUtils.isEmpty(detail.getRecurringDetailReference())) {
fail("Recurring detail does not contain any information.");
}
} else {
fail("No result details returned.");
}
}
}
Model (Root object)
public class RecurringDetailsResult
implements java.io.Serializable {
private static final long serialVersionUID = 5297684963950973136L;
private Date creationDate;
private String shopperReference;
private List<RecurringDetail> details;
private String lastKnownShopperEmail;
#JsonGetter("creationDate")
public Date getCreationDate ( ) {
return this.creationDate;
}
#JsonSetter("creationDate")
public void setCreationDate (Date value) {
this.creationDate = value;
}
#JsonGetter("shopperReference")
public String getShopperReference ( ) {
return this.shopperReference;
}
#JsonSetter("shopperReference")
public void setShopperReference (String value) {
this.shopperReference = value;
}
#JsonGetter("details")
public List<RecurringDetail> getDetails ( ) {
return this.details;
}
#JsonSetter("details")
public void setDetails (List<RecurringDetail> value) {
this.details = value;
}
#JsonGetter("lastKnownShopperEmail")
public String getLastKnownShopperEmail ( ) {
return this.lastKnownShopperEmail;
}
#JsonSetter("lastKnownShopperEmail")
public void setLastKnownShopperEmail (String value) {
this.lastKnownShopperEmail = value;
}
}
Model (the object in the array, all of the fields of this guy are null when Jackson deserializes the JSON)
public class RecurringDetail
implements java.io.Serializable {
private static final long serialVersionUID = 5302883242997268343L;
private String name;
private Date creationDate;
private Card card;
private ELV elv;
private Address billingAddress;
private String additionalData;
private Name shopperName;
private String socialSecurityNumber;
private String recurringDetailReference;
private BankAccount bank;
private String alias;
private String aliasType;
private TokenDetails tokenDetails;
private String variant;
private String paymentMethodVariant;
private String firstPspReference;
private List<String> contractTypes;
private String acquirer;
private String acquirerAccount;
#JsonGetter("name")
public String getName ( ) {
return this.name;
}
#JsonSetter("name")
public void setName (String value) {
this.name = value;
}
#JsonGetter("creationDate")
public Date getCreationDate ( ) {
return this.creationDate;
}
#JsonSetter("creationDate")
public void setCreationDate (Date value) {
this.creationDate = value;
}
#JsonGetter("card")
public Card getCard ( ) {
return this.card;
}
#JsonSetter("card")
public void setCard (Card value) {
this.card = value;
}
#JsonGetter("elv")
public ELV getElv ( ) {
return this.elv;
}
#JsonSetter("elv")
public void setElv (ELV value) {
this.elv = value;
}
#JsonGetter("billingAddress")
public Address getBillingAddress ( ) {
return this.billingAddress;
}
#JsonSetter("billingAddress")
public void setBillingAddress (Address value) {
this.billingAddress = value;
}
#JsonGetter("additionalData")
public String getAdditionalData ( ) {
return this.additionalData;
}
#JsonSetter("additionalData")
public void setAdditionalData (String value) {
this.additionalData = value;
}
#JsonGetter("shopperName")
public Name getShopperName ( ) {
return this.shopperName;
}
#JsonSetter("shopperName")
public void setShopperName (Name value) {
this.shopperName = value;
}
#JsonGetter("socialSecurityNumber")
public String getSocialSecurityNumber ( ) {
return this.socialSecurityNumber;
}
#JsonSetter("socialSecurityNumber")
public void setSocialSecurityNumber (String value) {
this.socialSecurityNumber = value;
}
#JsonGetter("recurringDetailReference")
public String getRecurringDetailReference ( ) {
return this.recurringDetailReference;
}
#JsonSetter("recurringDetailReference")
public void setRecurringDetailReference (String value) {
this.recurringDetailReference = value;
}
#JsonGetter("bank")
public BankAccount getBank ( ) {
return this.bank;
}
#JsonSetter("bank")
public void setBank (BankAccount value) {
this.bank = value;
}
#JsonGetter("alias")
public String getAlias ( ) {
return this.alias;
}
#JsonSetter("alias")
public void setAlias (String value) {
this.alias = value;
}
#JsonGetter("aliasType")
public String getAliasType ( ) {
return this.aliasType;
}
#JsonSetter("aliasType")
public void setAliasType (String value) {
this.aliasType = value;
}
#JsonGetter("tokenDetails")
public TokenDetails getTokenDetails ( ) {
return this.tokenDetails;
}
#JsonSetter("tokenDetails")
public void setTokenDetails (TokenDetails value) {
this.tokenDetails = value;
}
#JsonGetter("variant")
public String getVariant ( ) {
return this.variant;
}
#JsonSetter("variant")
public void setVariant (String value) {
this.variant = value;
}
#JsonGetter("paymentMethodVariant")
public String getPaymentMethodVariant ( ) {
return this.paymentMethodVariant;
}
#JsonSetter("paymentMethodVariant")
public void setPaymentMethodVariant (String value) {
this.paymentMethodVariant = value;
}
#JsonGetter("firstPspReference")
public String getFirstPspReference ( ) {
return this.firstPspReference;
}
#JsonSetter("firstPspReference")
public void setFirstPspReference (String value) {
this.firstPspReference = value;
}
#JsonGetter("contractTypes")
public List<String> getContractTypes ( ) {
return this.contractTypes;
}
#JsonSetter("contractTypes")
public void setContractTypes (List<String> value) {
this.contractTypes = value;
}
#JsonGetter("acquirer")
public String getAcquirer ( ) {
return this.acquirer;
}
#JsonSetter("acquirer")
public void setAcquirer (String value) {
this.acquirer = value;
}
#JsonGetter("acquirerAccount")
public String getAcquirerAccount ( ) {
return this.acquirerAccount;
}
#JsonSetter("acquirerAccount")
public void setAcquirerAccount (String value) {
this.acquirerAccount = value;
}
}

The easiest thing I can think to do is to make your java objects look like your Json. Because this Json has a wrapped inner object but not the outer object you would have to have a similar wrapping in java. It isn't elegant but works.
public class RecurringDetailsResult implements java.io.Serializable {
private Date creationDate;
private String shopperReference;
private List<RecurringDetailWrapper> details;
private String lastKnownShopperEmail;
// getters and setters here. No need for any #JsonGetter or #JsonSetter annotations
}
#JsonRootName("RecurringDetail")
public class RecurringDetailWrapper {
#JsonProperty("RecurringDetail")
RecurringDetail recurringDetail;
public RecurringDetail getRecurringDetail() {
return recurringDetail;
}
public void setRecurringDetail(RecurringDetail recurringDetail) {
this.recurringDetail = recurringDetail;
}
}
public class RecurringDetail implements java.io.Serializable {
private static final long serialVersionUID = 5302883242997268343L;
private String name;
private Date creationDate;
private Card card;
private AdditionalData additionalData;
private String socialSecurityNumber;
private String recurringDetailReference;
private String alias;
private String aliasType;
private String variant;
private String paymentMethodVariant;
private String firstPspReference;
private List<String> contractTypes;
private String acquirer;
private String acquirerAccount;
public class AdditionalData {
String cardBin;
public String getCardBin() {
return cardBin;
}
public void setCardBin(String cardBin) {
this.cardBin = cardBin;
}
}
// getters and setters here. No need for any #JsonGetter or #JsonSetter annotations
}
Then in your unit test:
#Test
public void testParseRecurringDetailResulte() throws IOException {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("ID41901838.json");
ObjectReader objectReader = mapper.readerFor(RecurringDetailsResult.class);
RecurringDetailsResult result = objectReader.readValue(inputStream);
if (result.getDetails() != null && !result.getDetails().isEmpty()) {
RecurringDetailWrapper detail = result.getDetails().get(0);
if (StringUtils.isEmpty(detail.getRecurringDetail().getRecurringDetailReference())) {
fail("Recurring detail does not contain any information.");
}
} else {
fail("No result details returned.");
}
}
I posted the full working code here:
https://github.com/teacurran/java-experiments/tree/master/stackoverflow-sandbox/src/main/java/com/wirelust/stackoverflowsandbox/ID41901838

It seems your current structure will work for the response JSON as below (an extra named layer is removed)
{
"creationDate": "2017-01-26T23:11:20+01:00",
"details": [
{
"acquirer": "TestPmmAcquirer",
"acquirerAccount": "TestPmmAcquirerAccount",
"additionalData": {
"cardBin": "440000"
},
"alias": "B133243153928547",
"aliasType": "Default",
"card": {
"expiryMonth": "8",
"expiryYear": "2018",
"holderName": "Steve HAll",
"number": "0008"
},
"contractTypes": [
"RECURRING"
],
"creationDate": "2017-01-26T23:11:20+01:00",
"firstPspReference": "8524854686798738",
"paymentMethodVariant": "visadebit",
"recurringDetailReference": "8414854686802111",
"variant": "visa"
}
],
"invalidOneclickContracts": "false",
"lastKnownShopperEmail": "someones#email.com",
"shopperReference": "xggZcGauSSG5jP+akIlijQ=="
}
For named object maybe you can try something like
public class RecurringDetailsResult
implements java.io.Serializable {
private static final long serialVersionUID = 5297684963950973136L;
private Date creationDate;
private String shopperReference;
private List<Map<String,RecurringDetail>> details;
private String lastKnownShopperEmail;
#JsonGetter("creationDate")
public Date getCreationDate ( ) {
return this.creationDate;
}
#JsonSetter("creationDate")
public void setCreationDate (Date value) {
this.creationDate = value;
}
#JsonGetter("shopperReference")
public String getShopperReference ( ) {
return this.shopperReference;
}
#JsonSetter("shopperReference")
public void setShopperReference (String value) {
this.shopperReference = value;
}
#JsonGetter("details")
public List<Map<String, RecurringDetail>> getDetails ( ) {
return this.details;
}
#JsonSetter("details")
public void setDetails (List<Map<String, RecurringDetail>> value) {
this.details = value;
}
#JsonGetter("lastKnownShopperEmail")
public String getLastKnownShopperEmail ( ) {
return this.lastKnownShopperEmail;
}
#JsonSetter("lastKnownShopperEmail")
public void setLastKnownShopperEmail (String value) {
this.lastKnownShopperEmail = value;
}
}

Related

Elasticsearch improve search accuracy on Boolean query match, matchesNot, matchesPartial

Need a help about the implementation of how to improve the search accuracy of the elasticSearch logic on the JAVA side which is in the springboot application.
Why I am aiming for search accuracy? Because in the production side whenever I am searching for products using the search bar in the app ex. Laptops it shows different results of product also.
First I have a **controller class ** where the request goes to this endpoint:
#PostMapping("/bsl/view/products/sort-filter")
public Response<SearchByFilterByResponse> viewSortByFilterBy(#RequestBody SearchByDto searchBy) throws IOException{
return Response.success(elasticSearchProductBslService.viewSortByFilterBy(searchBy));
}
RequestBody contains the SearchByDto class where inside of that class I have the filterBy object, where inside of it the structure of query is there.
SearchByDto class:
SearchByDto class
FilterBy class:
private Map<String, List<String>> filter;
private List<KeyValue<String, String>> matches;
private List<KeyValue<String, String>> matchesPartial;
private List<KeyValue<String, String>> matchesNot;
private List<KeyValue<String, RangeValue>> ranges;
private List<String> discludeFieldNotNullAndEmpty;
public List<String> getDiscludeFieldNotNullAndEmpty() {
if(discludeFieldNotNullAndEmpty==null) {
this.discludeFieldNotNullAndEmpty = new ArrayList<>();
}
return discludeFieldNotNullAndEmpty;
}
public void setDiscludeFieldNotNullAndEmpty(List<String> discludeFieldNotNullAndEmpty) {
this.discludeFieldNotNullAndEmpty = discludeFieldNotNullAndEmpty;
}
public List<KeyValue<String, RangeValue>> getRanges() {
if(ranges==null) {
this.ranges = new ArrayList<>();
}
return ranges;
}
public void setRanges(List<KeyValue<String, RangeValue>> ranges) {
this.ranges = ranges;
}
public Map<String, List<String>> getFilter() {
if(filter==null) {
this.filter = new HashMap<>();
}
return filter;
}
public void setFilter(Map<String, List<String>> filter) {
this.filter = filter;
}
public List<KeyValue<String, String>> getMatches() {
if(matches==null) {
this.matches = new ArrayList<>();
}
return matches;
}
public void setMatches(List<KeyValue<String, String>> matches) {
this.matches = matches;
}
public List<KeyValue<String, String>> getMatchesPartial() {
if(matchesPartial==null) {
this.matchesPartial = new ArrayList<>();
}
return matchesPartial;
}
public void setMatchesPartial(List<KeyValue<String, String>> matchesPartial) {
this.matchesPartial = matchesPartial;
}
public List<KeyValue<String, String>> getMatchesNot() {
if(matchesNot==null) {
this.matchesNot = new ArrayList<>();
}
return matchesNot;
}
public void setMatchesNot(List<KeyValue<String, String>> matchesNot) {
this.matchesNot = matchesNot;
}
}
As based on the structure of the code the matches, matchesPartial, matchesNot is nested under the filter Map, and each keyword queries should have key and value.
Now let's go back to the controller class, as you can see inside of the Response.success method
it is calling also the elasticSearchProductBslService.viewSortByFilterBy(searchBy) where inside of the searchBy it contains the request including the filterBy.
Let's jump to the viewSortByFilterBy() method inside of the elasticSearchProductBslService class.
public SearchByFilterByResponse viewSortByFilterBy(SearchByDto searchBy) throws IOException{
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
SearchRequest request = new SearchRequest();
request.indices("product_bsl");
request.source(sourceBuilder);
int fromIndex = searchBy.getPagination().getFrom();
int size = searchBy.getPagination().getSize();
elasticSearchHelper.buildFieldSort(searchBy, sourceBuilder);
sourceBuilder.from(fromIndex);
sourceBuilder.size(size);
BoolQueryBuilder queryBuilder = elasticSearchHelper.boolQueryBuilder(searchBy);
sourceBuilder.query(queryBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);
SearchHit[] searchHits = response.getHits().getHits();
SearchByFilterByResponse resp = new SearchByFilterByResponse();
resp.setTotalHits(response.getHits().getTotalHits().value);
List<ProductWithImage> products = searchHitToDto(searchHits);
resp.setProducts(products);
return resp;
}
Additional information for you, this is the DTO class for "product_bsl" index. As I will show it to you how it look like in the OpenAPI later.
ProductBslElasticDto class:
public class ProductBslElasticDto {
private String id;
private String name;
private List<OfferElasticDto> offers;
private List<ProductBslElasticCategory> productBslElasticCategory;
private String brandId;
private String brandName;
private String shortdesc;
private String longDesc;
private int brandRating;
private long dateInserted;
private List<String> imagePath;
private String isActive;
private List<String> images;
private List<String> imageId;
private long totalVisits;
private long totalVisitUpdateTime;
private long totalViewCount;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getShortdesc() {
return shortdesc;
}
public void setShortdesc(String shortdesc) {
this.shortdesc = shortdesc;
}
public String getLongDesc() {
return longDesc;
}
public void setLongDesc(String longDesc) {
this.longDesc = longDesc;
}
public int getBrandRating() {
return brandRating;
}
public void setBrandRating(int brandRating) {
this.brandRating = brandRating;
}
public String getBrandId() {
return brandId;
}
public void setBrandId(String brandId) {
this.brandId = brandId;
}
public long getDateInserted() {
return dateInserted;
}
public void setDateInserted(long dateInserted) {
this.dateInserted = dateInserted;
}
public List<ProductBslElasticCategory> getProductBslElasticCategory() {
return productBslElasticCategory;
}
public void setProductBslElasticCategory(List<ProductBslElasticCategory> productBslElasticCategory) {
this.productBslElasticCategory = productBslElasticCategory;
}
public long getTotalVisits() {
return totalVisits;
}
public void setTotalVisits(long totalVisits) {
this.totalVisits = totalVisits;
}
public long getTotalVisitUpdateTime() {
return totalVisitUpdateTime;
}
public void setTotalVisitUpdateTime(long totalVisitUpdateTime) {
this.totalVisitUpdateTime = totalVisitUpdateTime;
}
public String getIsActive() {
return isActive;
}
public void setIsActive(String isActive) {
this.isActive = isActive;
}
public List<String> getImages() {
return images;
}
public void setImages(List<String> images) {
this.images = images;
}
public List<String> getImageId() {
return imageId;
}
public void setImageId(List<String> imageId) {
this.imageId = imageId;
}
public List<OfferElasticDto> getOffers() {
return offers;
}
public void setOffers(List<OfferElasticDto> offers) {
this.offers = offers;
}
public long getTotalViewCount() {
return totalViewCount;
}
public void setTotalViewCount(long totalViewCount) {
this.totalViewCount = totalViewCount;
}
public List<String> getImagePath() {
return imagePath;
}
public void setImagePath(List<String> imagePath) {
sortIndexedImagePaths(imagePath);
this.imagePath = imagePath;
}
private void sortIndexedImagePaths(List<String> imagePaths) {
if (null == imagePaths) return;
for (String path : imagePaths) {
if (null == path ||
!PRODUCT_INDEXED_IMAGE_PATH_PATTERN.matcher(path).find()) {
return;
}
}
imagePaths.sort(String::compareTo);
}
}
Now after I show the DTO you can look back to the viewSortByFilterBy() again. I think you can disregard the SourceBuilder and SearchRequest let's focus on the elasticSearchHelper.boolQueryBuilder(searchBy) as we will jump inside of it.
ElasticSearchHelper class:
#Service
public class ElasticSearchHelper {
private static final String KEY_NAME = "name";
private static final String REGEX_SPACE = " ";
private static final String REGEX_WILDCARD = "*";
public BoolQueryBuilder boolQueryBuilder(SearchByDto searchBy) {
FilterBy filterBy = searchBy.getFilterBy();
BoolQueryBuilder rootBuilder = QueryBuilders.boolQuery();
if(filterBy!=null) {
nestedTermsQueryBuilder(rootBuilder, filterBy.getFilter());
nestedBoolQueryBuilder(rootBuilder, filterBy.getMatches(), MUST);
nestedBoolQueryBuilder(rootBuilder, filterBy.getMatchesNot(), MUST_NOT);
nestedBoolQueryBuilder(rootBuilder, filterBy.getMatchesPartial(), SHOULD);
nestedExistsQueryBuilder(rootBuilder, filterBy.getDiscludeFieldNotNullAndEmpty());
nestedRangeQueryBuilder(rootBuilder, filterBy.getRanges());
}
return rootBuilder;
}
private void nestedTermsQueryBuilder(BoolQueryBuilder rootBuilder, Map<String, List<String>> filter) {
filter.forEach((key, value) -> {
TermsQueryBuilder nestedBuilder = QueryBuilders.termsQuery(key, value);
rootBuilder.must(nestedBuilder);
});
}
private void nestedBoolQueryBuilder(BoolQueryBuilder rootBuilder, List<KeyValue<String, String>> entries, ElasticSearchBoolQueryType queryType) {
if(entries != null && !entries.isEmpty()) {
Set<String> distinctKeys = entries.stream().map(KeyValue::getKey).collect(Collectors.toSet());
for (String key : distinctKeys) {
BoolQueryBuilder nestedBuilder = QueryBuilders.boolQuery();
for (KeyValue<String, String> entry : entries) {
nestedQueryStringOrDisMaxQueryBuilder(key, entry, nestedBuilder);
}
switch (queryType) {
case MUST:
rootBuilder.must(nestedBuilder);
break;
case MUST_NOT:
rootBuilder.mustNot(nestedBuilder);
break;
case SHOULD:
rootBuilder.should(nestedBuilder);
break;
default:
break;
}
}
}
}
I just included the boolQueryBuilder and nestedBoolQueryBuilder only just to focus relating to my concern. don't get confuse on the MUST, MUST_NOT, SHOULD it is the same for matches, matchesNot, matchesPartial as I have told earlier on the FilterBy class. So in this class I think the logic happens here, any suggestions for any changes and how should I improve search accuracy for this kind of structure?
How it looks like in OpenAPI as I will search for product name:
Request: POST "/bsl/view/products/sort-filter"
{
"pagination": {
"from": 0,
"size": 20
},
"sortBy": {
"fieldsAscOrDesc": {
"offers.financing.finalAmount": "desc"
}
},
"filterBy": {
"matches": [
{
"key": "name",
"value": "Lenovo IdeaPad3 81Y4001NPH"
}
],
"matchesNot": [
{
"key": "isActive",
"value": "false"
}
],
"discludeFieldNotNullAndEmpty": [
"offers"
]
}
}
Result was it had total of 17 hits and I used the matches keyword where it should be search the exact word right? But it shows different Lenovo products in the result.
Result

Java 17 java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.time.ZoneOffset

I have been trying to convert a json string to variables my java program can use but when i run this it doesnt work.
(responseString is a valid json string)
GetConversion conversion = new ObjectMapper().readValue(responseString, GetConversion.class);
class GetConversion{
private State state;
private Swupdate swupdate;
private String type;
private String name;
private String modelid;
private String manufacturername;
private String productname;
private Capabilities capabilities;
private Config config;
private String uniqueid;
private String swversion;
private String swconfigid;
private String productid;
public State getState() { return state; }
public void setState(State value) { this.state = value; }
public Swupdate getSwupdate() { return swupdate; }
public void setSwupdate(Swupdate value) { this.swupdate = value; }
public String getType() { return type; }
public void setType(String value) { this.type = value; }
public String getName() { return name; }
public void setName(String value) { this.name = value; }
public String getModelid() { return modelid; }
public void setModelid(String value) { this.modelid = value; }
public String getManufacturername() { return manufacturername; }
public void setManufacturername(String value) { this.manufacturername = value; }
public String getProductname() { return productname; }
public void setProductname(String value) { this.productname = value; }
public Capabilities getCapabilities() { return capabilities; }
public void setCapabilities(Capabilities value) { this.capabilities = value; }
public Config getConfig() { return config; }
public void setConfig(Config value) { this.config = value; }
public String getUniqueid() { return uniqueid; }
public void setUniqueid(String value) { this.uniqueid = value; }
public String getSwversion() { return swversion; }
public void setSwversion(String value) { this.swversion = value; }
public String getSwconfigid() { return swconfigid; }
public void setSwconfigid(String value) { this.swconfigid = value; }
public String getProductid() { return productid; }
public void setProductid(String value) { this.productid = value; }
}
class Capabilities {
private boolean certified;
private Control control;
private Streaming streaming;
public boolean getCertified() { return certified; }
public void setCertified(boolean value) { this.certified = value; }
public Control getControl() { return control; }
public void setControl(Control value) { this.control = value; }
public Streaming getStreaming() { return streaming; }
public void setStreaming(Streaming value) { this.streaming = value; }
}
class Control {
private long mindimlevel;
private long maxlumen;
private String colorgamuttype;
private double[][] colorgamut;
private CT ct;
public long getMindimlevel() { return mindimlevel; }
public void setMindimlevel(long value) { this.mindimlevel = value; }
public long getMaxlumen() { return maxlumen; }
public void setMaxlumen(long value) { this.maxlumen = value; }
public String getColorgamuttype() { return colorgamuttype; }
public void setColorgamuttype(String value) { this.colorgamuttype = value; }
public double[][] getColorgamut() { return colorgamut; }
public void setColorgamut(double[][] value) { this.colorgamut = value; }
public CT getCT() { return ct; }
public void setCT(CT value) { this.ct = value; }
}
class CT {
private long min;
private long max;
public long getMin() { return min; }
public void setMin(long value) { this.min = value; }
public long getMax() { return max; }
public void setMax(long value) { this.max = value; }
}
class Streaming {
private boolean renderer;
private boolean proxy;
public boolean getRenderer() { return renderer; }
public void setRenderer(boolean value) { this.renderer = value; }
public boolean getProxy() { return proxy; }
public void setProxy(boolean value) { this.proxy = value; }
}
class Config {
private String archetype;
private String function;
private String direction;
private Startup startup;
public String getArchetype() { return archetype; }
public void setArchetype(String value) { this.archetype = value; }
public String getFunction() { return function; }
public void setFunction(String value) { this.function = value; }
public String getDirection() { return direction; }
public void setDirection(String value) { this.direction = value; }
public Startup getStartup() { return startup; }
public void setStartup(Startup value) { this.startup = value; }
}
class Startup {
private String mode;
private boolean configured;
public String getMode() {
return mode;
}
public void setMode(String value) {
this.mode = value;
}
public boolean getConfigured() {
return configured;
}
public void setConfigured(boolean value) {
this.configured = value;
}
}
class State {
private boolean on;
private long bri;
private long hue;
private long sat;
private String effect;
private double[] xy;
private long ct;
private String alert;
private String colormode;
private String mode;
private boolean reachable;
public boolean getOn() { return on; }
public void setOn(boolean value) { this.on = value; }
public long getBri() { return bri; }
public void setBri(long value) { this.bri = value; }
public long getHue() { return hue; }
public void setHue(long value) { this.hue = value; }
public long getSat() { return sat; }
public void setSat(long value) { this.sat = value; }
public String getEffect() { return effect; }
public void setEffect(String value) { this.effect = value; }
public double[] getXy() { return xy; }
public void setXy(double[] value) { this.xy = value; }
public long getCT() { return ct; }
public void setCT(long value) { this.ct = value; }
public String getAlert() { return alert; }
public void setAlert(String value) { this.alert = value; }
public String getColormode() { return colormode; }
public void setColormode(String value) { this.colormode = value; }
public String getMode() { return mode; }
public void setMode(String value) { this.mode = value; }
public boolean getReachable() { return reachable; }
public void setReachable(boolean value) { this.reachable = value; }
}
class Swupdate {
private String state;
private OffsetDateTime lastinstall;
public String getState() { return state; }
public OffsetDateTime getLastinstall() { return lastinstall; }
}
I believe it may have something to do with the last part of the code "public OffsetDateTime getLastinstall() { return lastinstall; }" because the error mentions java.time.OffsetDateTime and this is where that is called.
When I run this it gives a this error:
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.time.ZoneOffset java.time.OffsetDateTime.offset accessible: module java.base does not "opens java.time" to unnamed module #3578436e
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
at com.fasterxml.jackson.databind.util.ClassUtil.checkAndFixAccess(ClassUtil.java:891)
at com.fasterxml.jackson.databind.deser.impl.FieldProperty.fixAccess(FieldProperty.java:102)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder._fixAccess(BeanDeserializerBuilder.java:484)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder.build(BeanDeserializerBuilder.java:350)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:245)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:137)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:411)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findNonContextualValueDeserializer(DeserializationContext.java:467)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:473)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:293)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findNonContextualValueDeserializer(DeserializationContext.java:467)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.resolve(BeanDeserializerBase.java:473)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:293)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:477)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:4190)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4009)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3004)
at sendCommands.Loft.runGet(Loft.java:141)
at sendCommands.Loft.routine(Loft.java:103)
at sendCommands.Main.main(Main.java:7)
Help fix this pls. The json I used for response string is :
{
"state": {
"on": true,
"bri": 198,
"hue": 25360,
"sat": 254,
"effect": "none",
"xy": [
0.1749,
0.6963
],
"ct": 500,
"alert": "none",
"colormode": "xy",
"mode": "homeautomation",
"reachable": true
},
"swupdate": {
"state": "noupdates",
"lastinstall": "2021-08-13T13:51:54"
},
"type": "Extended color light",
"name": "Hue color spot 6",
"modelid": "LCG002",
"manufacturername": "Signify Netherlands B.V.",
"productname": "Hue color spot",
"capabilities": {
"certified": true,
"control": {
"mindimlevel": 200,
"maxlumen": 300,
"colorgamuttype": "C",
"colorgamut": [
[
0.6915,
0.3083
],
[
0.17,
0.7
],
[
0.1532,
0.0475
]
],
"ct": {
"min": 153,
"max": 500
}
},
"streaming": {
"renderer": true,
"proxy": true
}
},
"config": {
"archetype": "spotbulb",
"function": "mixed",
"direction": "downwards",
"startup": {
"mode": "safety",
"configured": true
}
},
"uniqueid": "00:17:88:01:08:3f:fb:56-0b",
"swversion": "1.88.2",
"swconfigid": "4AF23F6F",
"productid": "Philips-LCG002-1-GU10ECLv2"
}
It looks to me like it's a problem with Jackson attempting to serialize an OffsetDateTime field - it's trying to access the OffsetDateTime's private 'offset' property.
Jackson needs to be told how to serialize OffsetDateTime properly.
You can either add another Jackson library dependency to take care of this, or write a custom object mapper, if you need a format not provided by the library.
See Jackson date-format for OffsetDateTime in Spring Boot
I encountered a similar issue when I was unit testing Twilio SMS.
I solved the issue by registering JavaTimeModule on the ObjectMapper.
String json = "{\"status\": \"sent\"}";
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
var message = Message.fromJson(json, mapper);

JSON serialize to a different value

I have the below json which im serializing
{
"name":"John",
"switch":"1"
},
{
"name":"Jim",
"switch":"0"
}
I want to serialize it to a differnt name So I had to do it like below
class Data {
private String name;
private String flag;
#JsonProperty("flag")
public byte getFlag() {
return flag;
}
#JsonProperty("switch")
public void setSwitch(String s) {
this.flag = flag;
}
}
So that I get it converted as below
{
"name":"John",
"flag":"1"
},
{
"name":"Jim",
"flag":"0"
}
Now I wanted to map the numic values to Y and N for 1 and 0 respectively. Can I acheive that ?
Im expecting my final string to be like this
{
"name":"John",
"switch":"Y"
},
{
"name":"Jim",
"switch":"N"
}
I agree with #Gaƫl J, but still if you want to go ahead this code change might help you to convert that 1/0 to Y/N.
public class Application {
#ToString
static class Input {
#JsonProperty("name")
private String name;
#JsonProperty("switch")
private String flag;
#JsonProperty("name")
public void setName(String name){
this.name = name;
}
#JsonProperty("switch")
public void setSwitch(String s) {
for(SwitchMap valuePair : SwitchMap.values()){
if(valuePair.getValue().equals(s)){
this.flag = valuePair.name();
}
}
}
}
public static void main(String[] args) throws JsonProcessingException {
String json = "{\n" +
"\"name\":\"John\",\n" +
"\"switch\":\"1\"\n" +
"}";
ObjectMapper mapper = new ObjectMapper();
Input in = mapper.readValue(json, Input.class);
System.out.println(mapper.writeValueAsString(in));
}
}
define an enum with the mapping
#Getter
public enum SwitchMap {
Y("1"),
N("0");
private final String value;
private SwitchMap(String value){
this.value = value;
}
}

How to handle NULL value in JSON Object using retrofit

I try to get a value from json using retrofit like this
holder.txtColor.setText(dataList.get(position).getProductColorMotor().getColorName());
But i got an error like this :
java.lang.String
com.qiscus.qismo.chat.data.model.ordermodel.ProductColorResponse.getColorName()'
on a null object reference
I assume it's because i got null from the JSON response :
...
"product_color_motor": null
...
The response will sometimes return NULL.
But normally the response is look like this :
...
"product_color_motor": {
"id": 315,
"product_variant_id": 9,
"md_model_code": "GW2",
"main_dealer_type": "Beat Pop ESP CW",
"color_id": 86,
"color_code": "PM",
"color_name": "Groovy Red White",
"color_hex_1": "#FFFFFF",
"color_hex_2": "#CC0000",
"parent_color": "Groovy Red White,Groovy,Red,White"
}
...
OrderListResponse.java
public class OrderListResponse {
#SerializedName("product_color_motor")
#Expose
private ProductColorResponse productColorMotor;
public ProductColorResponse getProductColorMotor() {
return productColorMotor;
}
public void setProductColorMotor(ProductColorResponse productColorMotor) {
this.productColorMotor = productColorMotor;
}
ProductColorResponse.java
public class ProductColorResponse {
#SerializedName("product_variant_id")
#Expose
private Integer productVariantId;
#SerializedName("color_id")
#Expose
private Integer colorId;
#SerializedName("color_code")
#Expose
private String colorCode;
#SerializedName("color_name")
#Expose
private String colorName;
#SerializedName("color_hex_1")
#Expose
private String colorHex1;
#SerializedName("color_hex_2")
#Expose
private String colorHex2;
#SerializedName("parent_color")
#Expose
private String parentColor;
public Integer getProductVariantId() {
return productVariantId;
}
public void setProductVariantId(Integer productVariantId) {
this.productVariantId = productVariantId;
}
public Integer getColorId() {
return colorId;
}
public void setColorId(Integer colorId) {
this.colorId = colorId;
}
public String getColorCode() {
return colorCode;
}
public void setColorCode(String colorCode) {
this.colorCode = colorCode;
}
public String getColorName() {
return colorName;
}
public void setColorName(String colorName) {
this.colorName = colorName;
}
public String getColorHex1() {
return colorHex1;
}
public void setColorHex1(String colorHex1) {
this.colorHex1 = colorHex1;
}
public String getColorHex2() {
return colorHex2;
}
public void setColorHex2(String colorHex2) {
this.colorHex2 = colorHex2;
}
public String getParentColor() {
return parentColor;
}
public void setParentColor(String parentColor) {
this.parentColor = parentColor;
}
}
How can i handle it, if it returns NULL ? Thanks.
Your call getProductColorMotor() can throw an exception. Do the following thing if you want safe Java code:
1) Mark the variable and getter as nullable
#SerializedName("product_color_motor")
#Nullable
private ProductColorResponse productColorMotor;
#Nullable
public ProductColorResponse getProductColorMotor() {
return productColorMotor;
}
2) Don't try to directly access getColorName(), instead, assign the productColorMotor to a variable.
ProductColorResponse p = dataList.get(position)
3) Now check if this is null and provide an alternative text to your txtColor
if (p == null) { holder.txtColor.setText("Alt text") } else { holder.txtColor.setText(p.getColorName())

Error when using DocumentReferences with Ektorp and JSF

I have been getting an error with DocumentReferences in a small JSF project i created to learn CouchDB/Ektorp .
I belive everything is working as is should in the CRUD, the id of the parent document is stored as a string, similar to the tutorial project.
But when I retrieve the parent object from the database I get this error:
org.codehaus.jackson.map.JsonMappingException: Can not instantiate value of type
[simple type, class com.pro.documents.Apple] from JSON String; no single-String
constructor/factory method (through reference chain: com.pro.documents.Eiere["apple"])
Here is the rest of the code:
{
"_id": "_design/Eiere",
"_rev": "17-ebb06b0d3102622a3d9849b9399cd94f",
"language": "javascript",
"views": {
"all": {
"map": "function(doc){if (doc.type == 'eiere') {emit(doc._id, doc);}}"
},
"ektorp_docrefs_apple": {
"map": "function(doc){ if(doc.eiere){emit([doc.eiere, 'apple', doc.kategori], null);}}"
}
}
}
{
"_id": "_design/Apple",
"_rev": "8-e04d8b5633776545b9eacdc998db4aea",
"language": "javascript",
"views": {
"all": {
"map": "function(doc){ if(doc.type == 'apple'){emit(doc._id, doc);}}"
}
}
}
public class Eiere extends CouchDbDocument {
#TypeDiscriminator
private String type;
private String navn;
private String telefon;
#DocumentReferences(backReference = "eiere", fetch = FetchType.LAZY, descendingSortOrder = true)
private Set<Apple> apple;
private Date dateCreated;
public Set<Apple> getApple() {
return apple;
}
public void setApple(Set<Apple> apples) {
this.apple = apples;
}
public void addApple(Apple c) {
Assert.notNull(c, "Apple may not be null");
if (getApple() == null) {
apple = new TreeSet<Apple>();
}
c.setEiere(this.getId());
apple.add(c);
}
public String getType() {
if (type == null) {
type = "eiere";
}
return type;
}
public void setType(String type) {
this.type = type;
}
public String getNavn() {
return navn;
}
public void setNavn(String navn) {
this.navn = navn;
}
public String getTelefon() {
return telefon;
}
public void setTelefon(String telefon) {
this.telefon = telefon;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
}
public class Apple extends CouchDbDocument implements Comparable<Apple>{
private static final long serialVersionUID = 1L;
#TypeDiscriminator
private String type;
private List<String> prices;
private String kategori;
private String eiere;
private Date dateCreated;
public String getType() {
if(type == null){
type = "apple";
}
return type;
}
public void setType(String type) {
this.type = type;
}
public List<String> getPrices() {
if(prices == null){
prices = new ArrayList<String>();
prices.add(0, " ");
prices.add(1, " ");
prices.add(2, " ");
}
return prices;
}
public void setPrices(List<String> prices) {
this.prices = prices;
}
public String getKategori() {
return kategori;
}
public void setKategori(String kategori) {
this.kategori = kategori;
}
public String getEiere() {
return eiere;
}
public void setEiere(String eiere) {
this.eiere = eiere;
}
#Override
public String toString() {
return prices.toString();
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
#Override
public int compareTo(Apple other) {
if (other == this) return 0;
if (dateCreated != null) {
return - dateCreated.compareTo(other.dateCreated);
}
return 0;
}
}
Any help or advice to help me understand what I'm doing wrong will be much appreciated.
Edit: If there is any information that I could add that would make my problem clearer or help in determining the cause of it please let me know.
Br.

Categories

Resources