Trying to serialize a collection of non-primitive types using katharsis, but getting an empty collection all the time.
Response example:
{
"data": {
"type": "products",
"id": "1",
"attributes": {
"simpleAttributes": [
{}
],
"variationGroup": "variationGroup"
},
"relationships": {},
"links": {
"self": "http://localhost:8080/api/products/1"
}
},
"included": []
}
Expected response:
{
"data": {
"type": "products",
"id": "1",
"attributes": {
"simpleAttributes": [
{
tittle: "some title",
value: "some value"
}
],
"variationGroup": "variationGroup"
},
"relationships": {},
"links": {
"self": "http://localhost:8080/api/products/1"
}
},
"included": []
}
Domain objects (getters, setters, constructor and other stuff omitted by using lombok #Data annotation):
#JsonApiResource(type = "products")
#Data
public class Product {
#JsonApiId
private Integer id;
private List<SimpleAttribute> simpleAttributes = new ArrayList<>();
private String variationGroup;
}
#Data
public class SimpleAttribute implements Serializable{
private String title;
private String value;
}
I do not want to use relationships in this case or to include attributes to "included" field. Is it possible in katharsis?
Not sure what actually was wrong, but the problem disappeared after I changed katharsis-spring version from 2.3.0 to 2.3.1.
Related
I have following JSON structure as input which can be nested and without nested. I want to fetch the JSON as input and process in Spring Boot application. How to create a class which dynamic key values in the JSON. It can be any key-value pairs in the JSON input. Below is the sample one.
Without Nested:
{
"mappings": {
"properties": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
},
"salary": {
"type": "integer"
},
"date_of_birth": {
"type": "date"
}
}
}
}
With Nested:
{
"mappings": {
"properties": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
},
"annual_salary": {
"type": "integer"
},
"date_of_birth": {
"type": "date"
},
"comments": {
"type": "nested",
"properties": {
"name": {
"type": "string"
},
"comment": {
"type": "string"
},
"age": {
"type": "short"
},
"stars": {
"type": "short"
},
"date": {
"type": "date"
}
}
}
}
}
}
I don't know how to create a class to support both with and without nested in single class. I have tried the following. It doesn't help.
public class Schema {
Mapping mappings;
public Mapping getMappings() {
return mappings;
}
public void setMappings(Mapping mappings) {
this.mappings = mappings;
}
public static class Mapping {
Property properties;
public Property getProperties() {
return properties;
}
public void setProperties(Property properties) {
this.properties = properties;
}
}
public static class Property {
Map<String, Map<String, Object>> field = new HashMap<>();
public Map<String, Map<String, Object>> getField() {
return field;
}
public void setField(Map<String, Map<String, Object>> field) {
this.field = field;
}
}
}
I have come across a scenario similar to this where it was possible that my JSON may not be having consistent Key-Value pairs.
I gave the following jackson annotation at class level so that whichever property not available in my model and which are present in the JSON will be ignored.
#JsonIgnoreProperties(ignoreUnknown = true)
there is possibility to deserialize Json only choosen fields?
Eg:
{
"Version": 1,
"Key": "353301_PC",
"Type": "PostalCode",
"Rank": 500,
"LocalizedName": "Kleosin",
"EnglishName": "Kleosin",
"PrimaryPostalCode": "16-001",
"Region": {
"ID": "EUR",
"LocalizedName": "Europe",
"EnglishName": "Europe"
}
And i want only LocalizedName and EnglishName. Tried with objectMapper but getting errors.
Add JsonIgnoreProperties annotation to your data class
#JsonIgnoreProperties(ignoreUnknown = true)
public class YourClass {
private String LocalizedName;
private String EnglishName;
...
}
you can add #JsonIgnore to the fields inside the Region class
I would like to create following json payload from the java classes. Only one condition is there, Subgroup1 can be null, meaning group may/may not have subgroup1. Not sure how can it be done. Any help would be highly appreciated. Thanks in advance! I can change the classes if needed.
{
"data" : [
{
"id": "1",
"name": "ab",
"children": [
{
"id": "1",
"name": "xyz",
"children": [
{ "id": "1",
"name": "opl"
} ]
}
]
},
{
"id":" 2",
"name": "cd",
"children": [
{
"id": "1",
"name": "ijk",
"children": [
{ "id": "1",
"name": "rty"},
{ "id": "2",
"name": "wsc"
} ]
},
{
"id": "2",
"name": "lmn",
"children": [
{ "id": "1",
"name": "qaz"},
{ "id": "2",
"name": "poi"
} ]
},
{
"id": "3",
"name": "opq",
"children": [
{ "id": "1",
"name": "edf"},
{ "id": "2",
"name": "bhgga"
} ]
}
]
},
{
"id": "3",
"name": "ef",
"children": [
{
"id": null,
"name": null,
"children": [
{ "id": "2",
"name": "ijyuht"
} ]
}
]
}
]
}
I have 3 different java classes to map objects.
Data.class
public class Data {
private Long id;
private String name;
private List<Subgroup1> children;
}
Subgroup1.class
public class Subgroup1 {
private Long id;
private String name;
private List<Subgroup2> children;
}
Subgroup2.class
public class Subgroup2 {
private Long id;
private String name;
}
Create Classes structure as below:
public class MainClass {
private List<Datum> data;
}
public class Datum {
private List<Child> children;
private String id;
private String name;
}
public class Child {
private List<Child> children;
private String id;
private String name;
}
below format you can use in Java, its just a way you can do it in multiples way, as i have expained in a easy way.
MainClass mainClass = new MainClass();
List<Child> level2List = new ArrayList<>();
Child level2Child = new Child();
level2Child.setName("opl");
level2Child.setId("1");
level2List.add(level2Child);
List<Child> childList = new ArrayList<>();
Child child = new Child();
child.setChildren(level2List);
child.setId("1");
child.setName("xyz");
childList.add(child);
Datum datum = new Datum();
datum.setChildren(childList);
datum.setId("1");
datum.setName("ab");
List<Datum> datumList = new ArrayList<>();
datumList.add(datum);
mainClass.setData(datumList);
System.out.println(new Gson().toJson(mainClass));
I am trying to download a JSON file with the latest news from a link, and then fill a news page with news articles from the JSON file, but I can't get it to work.
This is my JSON file:
[
"sections": {
{
"title": "category 1",
"color": 2,
"posts": [
{
"title": "Test 1",
"date": 17-09-2019,
"images": {
"launcher_preview": "testimage.png",
"imageName2": "testimage.png"
},
"href": "https://testlink.com"
},
{
"title": "Test 2",
"date": 17-09-2019,
"images": {
"launcher_preview": "testimage2.png",
"imageName2": "testiamge2.png"
},
"href": "https://testlink2.com"
}
]
},
{
"title": "category 2",
"color": 2,
"posts": [
{
"title": "Test 3",
"date": 17-09-2019,
"images": {
"launcher_preview": "testimage3.png",
"imageName2": "testimage3.png"
},
"href": "https://testlink3.com"
}
]
}
}
]
My java class (Only included the necessary part):
public class NewsFeedManager extends ImageCache {
private static final String METADATA_URL = "https://Linkhiddenforprivacy.com/news/latest.json",
IMAGE_PROVIDER_URL = "https://Linkhiddenforprivacy.com/news/images/";
private static final int CACHE_TIME = 1000 * 60 * 20;
private final ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
#JsonProperty
#Getter
private NewsFeed feed = new NewsFeed();
private Path imageCacheDir;
public NewsFeedManager() {
}
public static NewsFeedManager load(Launcher launcher) {
NewsFeedManager manager = Persistence.load(new File(launcher.getCacheDir(), "news_feed.json"), NewsFeedManager.class);
manager.imageCacheDir = Paths.get(launcher.getCacheDir().getAbsolutePath(), "launcher/news/images");
return manager;
}
public ListenableFuture<NewsFeed> refresh(boolean force) {
if (!force && this.feed != null && this.feed.expires > System.currentTimeMillis()) {
return Futures.immediateFuture(this.feed);
}
ListenableFuture<NewsFeed> future = this.executor.submit(() -> {
log.info("Fetching latest news feed from " + METADATA_URL);
NewsFeed feed = HttpRequest.get(HttpRequest.url(METADATA_URL))
.execute()
.expectResponseCode(200)
.returnContent()
.asJson(NewsFeed.class);
feed.expires = System.currentTimeMillis() + CACHE_TIME;
return feed;
});
Futures.addCallback(future, new FutureCallback<NewsFeed>() {
#Override
public void onSuccess(#Nullable NewsFeed result) {
NewsFeedManager.this.feed = result;
NewsFeedManager.this.save();
}
#Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
});
return future;
}
public ListenableFuture<Image> getImage(String resource) {
String remote = IMAGE_PROVIDER_URL + resource;
log.info("Fetching latest image feed from " + remote);
return this.obtain(resource, remote, false);
}
private void save() {
Persistence.commitAndForget(this);
}
public void clear() {
this.feed = null;
this.clearImageCache();
}
#Override
protected long getMaxCacheTime() {
return CACHE_TIME;
}
#Override
protected Path getImageCacheFolder() {
return this.imageCacheDir;
}
public static class NewsFeed {
#JsonProperty
#Getter
private List<NewsSection> sections;
#JsonProperty
private long expires;
}
public static class NewsSection {
#JsonProperty
#Getter
private String title;
#JsonProperty
#Getter
private int color;
#JsonProperty
#JsonManagedReference
#Getter
private List<NewsPost> posts;
}
public static class NewsPost {
#JsonProperty
#Getter
private String title;
#JsonProperty
#Getter
private Date date;
#JsonProperty
#Getter
private Map<String, String> images;
#JsonProperty
#Getter
private String href;
#JsonBackReference
#Getter
private NewsSection section;
}
I get this error when the client tries to fetch the news:
[info] Fetching latest news feed from https://linkhiddenforprivacy.com/news/latest.json
com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.hiddenforprivacy.launcher.ui.resources.NewsFeedManager$NewsFeed out of START_ARRAY token
at [Source: java.io.StringReader#4ac13260; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:691)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:685)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromArray(BeanDeserializerBase.java:1215)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:151)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:126)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2986)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2091)
at com.skcraft.launcher.util.HttpRequest$BufferedResponse.asJson(HttpRequest.java:479)
at com.hiddenforprivacy.launcher.ui.resources.NewsFeedManager.lambda$refresh$0(NewsFeedManager.java:61)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
I am not sure what is causing the error, I think my JSON is not correctly formatted, but I am not sure, can anyone here see what is causing this error?
Thank you for your time,
Piet
If your object is in an array, you can't assign a key to it. As a result, your HttpRequest.asJson() is failing. I have edited your JSON to return your sections as an array of objects instead of a single array object containing the sections.
Also, you can't have dates as numbers in a JSON file. I converted them into strings as well. For standardization purposes, make sure you store the date as an ISO 8601 string in your actual file.
Try this edited version of your JSON:
[
{
"title": "category 1",
"color": 2,
"posts": [{
"title": "Test 1",
"date": "17-09-2019",
"images": {
"launcher_preview": "testimage.png",
"imageName2": "testimage.png"
},
"href": "https://testlink.com"
},
{
"title": "Test 2",
"date": "17-09-2019",
"images": {
"launcher_preview": "testimage2.png",
"imageName2": "testiamge2.png"
},
"href": "https://testlink2.com"
}
]
},
{
"title": "category 2",
"color": 2,
"posts": [{
"title": "Test 3",
"date": "17-09-2019",
"images": {
"launcher_preview": "testimage3.png",
"imageName2": "testimage3.png"
},
"href": "https://testlink3.com"
}]
}
]
[
"sections": {
{
I see two problems at the very start of the file.
One, the first character is a square bracket, indicating that the contained values will be a simple list. But then it goes straight into "sections" : {, which is a key/value syntax, indicating that we ought to be in a dictionary/hashmap context. But we aren't; we're in a list context.
Second, there are two opening braces following "sections":. What is the second one meant to indicate?
I see three problems
1. The wrong bracket around json object.
2. Sections is an array, but is missing the array syntax.
3. Date String is not a valid object type, the string should be wrapped with quotes.
Properly formatted json for an object with sections which is an array of two sections.
{"sections": [
{
"title": "category 1",
"color": 2,
"posts": [
{
"title": "Test 1",
"date": "17-09-2019",
"images": {
"launcher_preview": "testimage.png",
"imageName2": "testimage.png"
},
"href": "https://testlink.com"
},
{
"title": "Test 2",
"date": "17-09-2019",
"images": {
"launcher_preview": "testimage2.png",
"imageName2": "testiamge2.png"
},
"href": "https://testlink2.com"
}
]
},
{
"title": "category 2",
"color": 2,
"posts": [
{
"title": "Test 3",
"date": "17-09-2019",
"images": {
"launcher_preview": "testimage3.png",
"imageName2": "testimage3.png"
},
"href": "https://testlink3.com"
}
]
}]
}
I have the following JSON structure:
{
"status": "Completed",
"notes": null,
"members": {
"0": {
"year": "2",
"details": {
"id": "14899975",
"anotherId": "11013306"
},
"aName": "Fred",
"amounts": {
"First": 589.48,
"Second": 1000,
"Third": 339.48
}
},
"1": {
"year": "2",
"details": {
"id": "14899976",
"anotherId": "11013306"
},
"aName": "George",
"amounts": {
"First": 222.22,
"Second": 2000,
"Third": 22.22
}
},
"2": {
"year": 1,
"details": {
"id": "14899976",
"anotherId": "11013306"
},
"aName": "Albert",
"amounts": {
"First": 333.33,
"Second": 3000,
"Third": 33.33
},
}
}
}
I am using Spring RESTTemplate and JacksonMapping2HttpMessageConverter, and the following structures to receive the result of parsing the above JSON structure:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Response {
private String status;
private String notes;
private Map<String,Struct1> quotes;
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Struct1 {
private int year;
private Struct2 details;
private String aName;
private Struct3 amounts;
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Struct2 {
private String id;
private String anotherId;
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Struct3 {
private float First;
private float Second;
private float Third;
}
All of these also have appropriate setters and getters for all fields.
My problem is that the number values in Struct3 are not filled in. I've tried making them float, Float, String, and BigDecimal, and the result is either null or 0.0.
I've tried putting a breakpoint in the setter for the first field, hoping
What am I missing? Can the capital letters in the JSON be causing a problem, do I need alternate field names?
It turned out to be the capital letters at the beginning of the field names; I added annotations like #JsonProperty("First") on the line before the getter of the field, and renamed the field to first, and now it's working.