Convert denormalized or flat data to hierarchical Java Object - java

This is what tried I did to convert a denormalized or flat data to hierarchical Java Object?
Here is the input, output and code, (question is at the bottom)
INPUT:
[ {
"countryName" : "USA",
"stateName" : "FL",
"cityName" : "Miami"
}, {
"countryName" : "USA",
"stateName" : "FL",
"cityName" : "Doral"
}, {
"countryName" : "India",
"stateName" : "Tamilnadu",
"cityName" : "Chennai"
}, {
"countryName" : "India",
"stateName" : "Karnataka",
"cityName" : "Bangalore"
} ]
OUTPUT:
[ {
"countryName" : "USA",
"states" : [ {
"stateName" : "FL",
"cities" : [ {
"cityName" : "Miami"
}, {
"cityName" : "Doral"
} ]
} ]
}, {
"countryName" : "India",
"states" : [ {
"stateName" : "Karnataka",
"cities" : [ {
"cityName" : "Bangalore"
} ]
}, {
"stateName" : "Tamilnadu",
"cities" : [ {
"cityName" : "Chennai"
} ]
} ]
} ]
CODE:
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toSet;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.Data;
public class Normalizer {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
final var objectWriter = objectMapper.writerWithDefaultPrettyPrinter();
Tuple t1 = Tuple.of("USA", "FL", "Miami");
Tuple t2 = Tuple.of("USA", "FL", "Doral");
Tuple t3 = Tuple.of("India", "Tamilnadu", "Chennai");
Tuple t4 = Tuple.of("India", "Karnataka", "Bangalore");
List<Tuple> tuples = List.of(t1, t2, t3, t4);
System.out.println("INPUT:\n" + objectWriter.writeValueAsString(tuples));
System.out.println("---------------------------------------------");
final var countries = normalize(tuples);
System.out.println("OUTPUT:\n" + objectWriter.writeValueAsString(countries));
}
public static Set<Country> normalize(List<Tuple> tuples) {
System.out.println("Step 1: Grouping");
final var map = tuples.stream()
.collect(groupingBy(Country::of, groupingBy(State::of, mapping(City::of, toSet()))));
System.out.println("Step 2: Creating Object Hierarchy");
Set<Country> countries = new HashSet<>();
map.forEach((country, value) -> {
countries.add(country);
Set<State> states = new HashSet<>();
value.forEach((state, value1) -> {
state.setCities(value1);
states.add(state);
});
country.setStates(states);
});
return countries;
}
#Data(staticConstructor = "of")
public static class Tuple {
private String countryName;
private String stateName;
private String cityName;
public static Tuple of(String countryName, String stateName, String cityName) {
Tuple t1 = new Tuple();
t1.setCountryName(countryName);
t1.setStateName(stateName);
t1.setCityName(cityName);
return t1;
}
}
#Data(staticConstructor = "of")
public static class Country {
private String countryName;
private Set<State> states = new HashSet<>();
public static Country of(Tuple tuple) {
Country country = new Country();
country.setCountryName(tuple.getCountryName());
return country;
}
}
#Data(staticConstructor = "of")
public static class State {
private String stateName;
private Set<City> cities = new HashSet<>();
public static State of(Tuple tuple) {
State state = new State();
state.setStateName(tuple.getStateName());
return state;
}
}
#Data(staticConstructor = "of")
public static class City {
private String cityName;
public static City of(Tuple tuple) {
City city = new City();
city.setCityName(tuple.getCityName());
return city;
}
}
}
There are 2 steps in normalize method, is there a way to get this in one step. Like, is there a way to get it just by using Java 8+ Collectors methods?

Related

How can I match search result in Elasticsearch to the Java Model?

Firstly, my project has MinIO server where I use minio api to upload my files via spring boot application. The MinIO server integrated with Elasticsearch. When I uploaded a file, MinIO automatically update Elasticsearch minio_events index (I have configured this settings before). I want to run following query in my spring boot application and match result into File.java:
POST http://localhost:9200/minio_events/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"Records.s3.object.userMetadata.X-Amz-Meta-Filename": "myfile.txt"
}
},
{
"match": {
"Records.s3.object.userMetadata.X-Amz-Meta-User_id": "40b3c4e0-fea8-4aca-9dec-b4b905f33df0"
}
}
]
}
},
"fields": [
"Records.s3.object.userMetadata.X-Amz-Meta-Filename",
"Records.s3.object.userMetadata.X-Amz-Meta-Description",
"Records.s3.object.userMetadata.X-Amz-Meta-Foldername",
"Records.s3.object.userMetadata.X-Amz-Meta-Tags",
"Records.s3.object.userMetadata.X-Amz-Meta-User_id"
],
"_source": false
}
The query result is:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.7260925,
"hits": [
{
"_index": "minio_events",
"_type": "_doc",
"_id": "AUuxte4_W8625RK6e6oT7tCJmJkSQJ0L9LGx6eAf0Dw=",
"_score": 1.7260925,
"fields": {
"Records.s3.object.userMetadata.X-Amz-Meta-Foldername": [
"helloworld"
],
"Records.s3.object.userMetadata.X-Amz-Meta-Description": [
"des"
],
"Records.s3.object.userMetadata.X-Amz-Meta-User_id": [
"40b3c4e0-fea8-4aca-9dec-b4b905f33df0"
],
"Records.s3.object.userMetadata.X-Amz-Meta-Filename": [
"MyFile.txt"
],
"Records.s3.object.userMetadata.X-Amz-Meta-Tags": [
"hello,world"
]
}
}
]
}
}
In my Spring Boot App, I wrote following repository class to fetch Elasticsearch results.
CustomFileRepository.java:
package com.oktaykcr.fileservice.repository;
import com.oktaykcr.fileservice.model.File;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
#Component
public class CustomFileRepository {
private final ElasticsearchOperations elasticsearchOperations;
private final List<String> fields = List.of(
"Records.s3.object.userMetadata.X-Amz-Meta-Filename",
"Records.s3.object.userMetadata.X-Amz-Meta-Description",
"Records.s3.object.userMetadata.X-Amz-Meta-Foldername",
"Records.s3.object.userMetadata.X-Amz-Meta-Tags",
"Records.s3.object.userMetadata.X-Amz-Meta-User_id"
);
public CustomFileRepository(ElasticsearchOperations elasticsearchOperations) {
this.elasticsearchOperations = elasticsearchOperations;
}
public List<File> findByFileNameAndUserId(String fileName, String userId) {
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("Records.s3.object.userMetadata.X-Amz-Meta-Filename", fileName))
.must(QueryBuilders.matchQuery("Records.s3.object.userMetadata.X-Amz-Meta-User_id", userId));
Query query = new NativeSearchQuery(queryBuilder);
query.setFields(fields);
SearchHits<File> result = elasticsearchOperations.search(query, File.class);
if(result.isEmpty()) {
return Collections.emptyList();
}
List<File> files = result.getSearchHits().stream().map(SearchHit::getContent).collect(Collectors.toList());
return files;
}
}
File.java:
package com.oktaykcr.fileservice.model;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import java.util.List;
#Document(indexName = "minio_events")
public class File {
#Id
private String id;
#Field(type = FieldType.Object, value = "fields")
private Fields fields;
public File() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Fields getFields() {
return fields;
}
public void setFields(Fields fields) {
this.fields = fields;
}
static class Fields {
#Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-Foldername")
public List<String> folderName;
#Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-Description")
public List<String> description;
#Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-User_id")
public List<String> userId;
#Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-Filename")
public List<String> fileName;
#Field(type = FieldType.Nested, value = "Records.s3.object.userMetadata.X-Amz-Meta-Tags")
public List<String> tags;
public Fields() {
}
public List<String> getFolderName() {
return folderName;
}
public void setFolderName(List<String> folderName) {
this.folderName = folderName;
}
public List<String> getDescription() {
return description;
}
public void setDescription(List<String> description) {
this.description = description;
}
public List<String> getUserId() {
return userId;
}
public void setUserId(List<String> userId) {
this.userId = userId;
}
public List<String> getFileName() {
return fileName;
}
public void setFileName(List<String> fileName) {
this.fileName = fileName;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
}
}
However, the result of List<File> files = customFileRepository.findByFileNameAndUserId(fileName, userId); is:
result = {ArrayList#15401} size = 1
0 = {File#15403}
id = "AUuxte4_W8625RK6e6oT7tCJmJkSQJ0L9LGx6eAf0Dw="
fields = null
id was mapped by #Document model but fields was not.

How to groupingBy collector to create a new field from the data?

I have data which arrives as such (list of maps):
{
“name”: “Hello”,
"source": “One”,
"status": “Good”,
“date”: "01-05-2021 7:35:58 PM"
},
{
“name”: “Hello”,
"source": “Two”,
"status": “Good”,
“date”: "01-05-2021 7:35:58 PM"
},
{
“name”: “Goodbye”,
"source": “Three”,
"status": “Bad”,
“date”: "01-05-2021 7:35:58 PM"
},
{
“name”: “Goodbye”,
"source": “Four”,
"status": “Bad”,
“date”: "01-05-2021 7:35:58 PM"
}
So I want to group this data by “name”, but also create a new field which collects the “source” and “status” fields into a list of objects. This would mean I'd have to map the inner data to a Java class as well (call these individual objects “sourceStatus” which I've already created a class for).
{
“name”: “Hello”,
“sourceStatuses”: [
{
“source”: ”One”,
“status”: ”Good”
},
{
“source”: ”Two”,
“status”: ”Good”
}
],
“status”: “Good”,
“date”: "01-05-2021 7:35:58 PM"
},
{
“name”: “Goodbye”,
“sourceStatuses”: [
{
“source”: ”Three”,
“status”: ”Bad”
},
{
“source”: ”Four”,
“status”: ”Bad”
}
],
“status” : “Bad,
“date”: "01-05-2021 7:35:58 PM"
}
I understand the groupingBy part can be done fairly straightforwardly with Java's Collector (https://www.baeldung.com/java-groupingby-collector), but I'm not sure how to achieve the resultant set for my use case, where I not only create a new field but am also collecting then mapping inner data to a class.
Edit: "date" and "status" are going to be the same for all items with the same "name".
I found no easy way to do it with just one grouping but here is a somewhat more complicated two stage solution.
public class Main {
public static void main(String[] args) {
List<Map<String, String>> data = new ArrayList<>();
data.add(newData("Hello", "One", "Good", "01-05-2021 7:35:58 PM"));
data.add(newData("Hello", "Two", "Good", "01-05-2021 7:35:58 PM"));
data.add(newData("Goodbye", "Three", "Bad", "01-05-2021 7:35:58 PM"));
data.add(newData("Goodbye", "Four", "Bad", "01-05-2021 7:35:58 PM"));
Map<Key, List<SourceStatus>> collected = data.stream()
.collect(Collectors.groupingBy(
m -> new Key(m.get("name"), m.get("status"), m.get("date")),
Collectors.collectingAndThen(Collectors.toList(), m -> m.stream().map(e -> new SourceStatus(e.get("source"), e.get("status"))).collect(Collectors.toList()))
));
List<CollectedData> finalCollection = collected.entrySet().stream()
.map(e -> new CollectedData(e.getKey().name, e.getValue(), e.getKey().status, e.getKey().date))
.collect(Collectors.toList());
finalCollection.forEach(System.out::println);
}
private static Map<String, String> newData(String name, String source, String status, String date) {
Map<String, String> map = new HashMap<>();
map.put("name", name);
map.put("source", source);
map.put("status", status);
map.put("date", date);
return map;
}
private static class Key {
private final String name;
private final String status;
private final String date;
public Key(String name, String status, String date) {
this.name = name;
this.status = status;
this.date = date;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
return Objects.equals(name, key.name) && Objects.equals(status, key.status) && Objects.equals(date, key.date);
}
#Override
public int hashCode() {
return Objects.hash(name, status, date);
}
}
}
Two more classes needed:
public class SourceStatus {
private final String source;
private final String status;
public SourceStatus(String source, String status) {
this.source = source;
this.status = status;
}
// Getters, equals/hashCode and toString
}
public class CollectedData {
private final String name;
private final List<SourceStatus> sourceStatuses;
private final String status;
private final String date;
public CollectedData(String name, List<SourceStatus> sourceStatuses, String status, String date) {
this.name = name;
this.sourceStatuses = sourceStatuses;
this.status = status;
this.date = date;
}
// Getters, equals/hashCode and toString
}
Not my finest code...
The key for the groupingBy collector should be another modifiable map without key "source" and the value should be a list of SourceStatus class, which can be collected using Collectors.mapping collector.
Note: Map's are used to represent a key and a final result deliberately.
Let's assume, SourceStatus has a custom constructor using Map<String, Object> as an argument to use it in the Collectors.mapping:
public class SourceStatus {
private String source;
private String status;
public SourceStatus(Map<String, Object> map) {
this.source = (String) map.get("source");
this.status = (String) map.get("status");
}
}
Then the code to get the resulting set of maps is as follows:
Set<Map<String, Object>> mapped = data
.stream()
.collect(Collectors.groupingBy(
m -> {
Map<String, Object> key = new LinkedHashMap<>();
key.putAll(m);
key.remove("source");
return key;
},
Collectors.mapping(SourceStatus::new, Collectors.toList())
))
.entrySet().stream()
.map(e -> {
e.getKey().put("sourceStatuses", e.getValue());
return e.getKey();
})
.collect(Collectors.toCollection(LinkedHashSet::new)); // maintain insertion order
// convert to json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mapped);
System.out.println(json);
Output:
[ {
"name" : "Hello",
"date" : "01-05-2021 7:35:58 PM",
"status" : "Good",
"sourceStatuses" : [ {
"source" : "1",
"status" : "Good"
}, {
"source" : "2",
"status" : "Good"
} ]
}, {
"name" : "Bye",
"date" : "01-05-2021 7:35:58 PM",
"status" : "Bad",
"sourceStatuses" : [ {
"source" : "3",
"status" : "Bad"
}, {
"source" : "4",
"status" : "Bad"
} ]
} ]

Aggregation results cannot properly map to Java object

I'm trying to get schedules data from mongoDb.
I created the appropriate aggregation and tried to convert it within Spring Framework.
db.theaters.aggregate([
{ $match: { 'city_id': <someCityId>, 'theatreRooms.schedules.spectacle_id': <someSpecId> } },
{ $unwind: '$theatreRooms' },
{ $unwind: '$theatreRooms.schedules' },
{ $group: { _id: { name: '$name', room: '$theatreRooms.name' }, schedules: { $addToSet: '$theatreRooms.schedules.time' } } },
{ $group: { _id: '$_id.name', schedules: { $addToSet: { room: '$_id.room', schedules: '$schedules' } } } }
])
I've created properly match and unwind operations. But I've got problem with first group operation.
It seems that the operation is well interpreted, but for some reason I am not able to properly map the _id object.
Here is my code example:
public class TheaterProject {
private TheaterId _id;
private List<String> schedules;
public TheaterId get_id() {
return _id;
}
public void set_id(TheaterId _id) {
this._id = _id;
}
public List<String> getSchedules() {
return schedules;
}
public void setSchedules(List<String> schedules) {
this.schedules = schedules;
}
}
public class TheaterId {
#Field("name")
private String name;
#Field("room")
private Integer room;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getRoom() {
return room;
}
public void setRoom(Integer room) {
this.room = room;
}
}
public Document getRawSchedules(String cityId, String spectaclesId){
MatchOperation match = Aggregation.match(Criteria.where("city_id").is(cityId).and("theatreRooms.schedules.spectacle_id").is(spectaclesId));
UnwindOperation theaterUnwind = Aggregation.unwind("theatreRooms");
UnwindOperation schedulesUnwind = Aggregation.unwind("theatreRooms.schedules");
GroupOperation firstGroup = Aggregation.group(Fields.from(
Fields.field("name", "name"),
Fields.field("room", "theatreRooms.name")))
.addToSet("theatreRooms.schedules.time").as("schedules");
Aggregation agg = Aggregation.newAggregation(match,theaterUnwind,schedulesUnwind,firstGroup);
Document theaters = mongoTemplate.aggregate(agg, Theater.class, TheaterProject.class).getRawResults();
return theaters;
}
public List<TheaterProject> getSchedules(String cityId, String spectaclesId){
MatchOperation match = Aggregation.match(Criteria.where("city_id").is(cityId).and("theatreRooms.schedules.spectacle_id").is(spectaclesId));
UnwindOperation theaterUnwind = Aggregation.unwind("theatreRooms");
UnwindOperation schedulesUnwind = Aggregation.unwind("theatreRooms.schedules");
GroupOperation firstGroup = Aggregation.group(Fields.from(
Fields.field("name", "name"),
Fields.field("room", "theatreRooms.name")))
.addToSet("theatreRooms.schedules.time").as("schedules");
Aggregation agg = Aggregation.newAggregation(match,theaterUnwind,schedulesUnwind,firstGroup);
List<TheaterProject> theaters = mongoTemplate.aggregate(agg, Theater.class, TheaterProject.class).getMappedResults();
return theaters;
}
When I've invoked method getSchedules which return mapped objects, _id field is equal to null.
[
{
"_id": null,
"schedules": [
"5:15"
]
},
{
"_id": null,
"schedules": [
"6:55",
"4:35",
"10:15"
]
}
]
But when I've invoked getRawSchedules which used getRawResults it's looking properly.
{
"results": [
{
"_id": {
"name": "Pinokio",
"room": 2
},
"schedules": [
"5:15"
]
},
{
"_id": {
"name": "Roma",
"room": 1
},
"schedules": [
"6:55",
"4:35",
"10:15"
]
}
]
}
I don't have any idea why it's working like that.
I didn't find any information about this problem in the documentation and here. But I have a solution. You may just rename the field from _id to something else. theaterId for example. I don't know all requirements for your issue but you may do it just on mapping level.
Fix the mapping
import org.springframework.data.mongodb.core.mapping.Field;
import java.util.List;
public class TheaterProject {
#Field("theaterId")
private TheaterId _id;
private List<String> schedules;
public TheaterId get_id() {
return _id;
}
public void set_id(TheaterId _id) {
this._id = _id;
}
public List<String> getSchedules() {
return schedules;
}
public void setSchedules(List<String> schedules) {
this.schedules = schedules;
}
}
But it requires additional projection step
public List<TheaterProject> getSchedules(String cityId, String spectaclesId){
...
GroupOperation firstGroup = Aggregation.group(Fields.from(
Fields.field("name", "name"),
Fields.field("room", "theatreRooms.name")))
.addToSet("theatreRooms.schedules.time").as("schedules");
ProjectionOperation projection = Aggregation.project(Fields.from(
Fields.field("theaterId", "_id"),
Fields.field("schedules", "schedules")));
Aggregation agg = Aggregation.newAggregation( ... ,firstGroup, projection);
List<TheaterProject> theaters = mongoTemplate.aggregate(agg, "collectionName", TheaterProject.class).getMappedResults();
return theaters;
}

Jackson Serialize List Entities (add field to root list)

this my entity
#Entity
public class Product extends AbstractBaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Type(type = "objectid")
private String id;
private String title;
my resources
#Path(value = ApiConstant.Urls.PRODUCTS)
public class ProductResource {
#Inject
private ProductService productService;
#GET
#Path(value = ApiConstant.Urls.PRODUCTS)
#Produces(value = MediaType.APPLICATION_JSON)
public List getProducts(){
return productService.findAll();
}
my json response
[ {
"id" : "596b6a02f70a0878590bcf08",
"title" : "test1",
"description" : "description test 1"
}, {
"id" : "596b6b00f70a087b72d377eb",
"title" : "test1",
"description" : "description test 1"
}, {
"id" : "596b6b75f70a087d40f580d5",
"title" : "test1",
"description" : "description test 1"
} ]
I want to create a count field that counts the items in the list
like this and add the list to the results field
{
"count": 3,
"results": [
{
"id" : "596b6a02f70a0878590bcf08",
"title" : "test1",
"description" : "description test 1"
}, {
"id" : "596b6b00f70a087b72d377eb",
"title" : "test1",
"description" : "description test 1"
}, {
"id" : "596b6b75f70a087d40f580d5",
"title" : "test1",
"description" : "description test 1"
} ],
}
I want to serialize the Product List returned by jpa persistence
You can use the following class to include a count along with a list of Product entities:
public class ResultList {
private int count;
#JsonProperty("results") private List<Product> products;
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = Objects.requireNonNull(products, "products");
this.count = products.size();
}
public int getCount() {
return count;
}
}
Class with generics type
public class ResultList<T> {
private int count;
#JsonProperty("results")
private List<T> items;
public List<T> getItems() {
return items;
}
public void setItems(List<T> items) {
this.items = Objects.requireNonNull(items, "items");
this.count = items.size();
}
public int getCount() {
return count;
}
}
ProductResource
#GET
#Path(value = ApiConstant.Urls.PRODUCTS)
#Produces(value = MediaType.APPLICATION_JSON)
public ResultList getProducts(){
List products = productService.findAll();
ResultList result = new ResultList<Product>();
result.setItems(products);
return result;
}
Thanks #ck1

Create a json array

I'm writing a code where in there has to be a main array generated in json. my code is as below.
My pojos
JsonCreator.java
package com.createjson;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "EntityLabels", "ExampleText", "SelectedIntentName" })
public class Jsoncreator {
#JsonProperty("EntityLabels")
private List<EntityLabel> entityLabels = null;
#JsonProperty("ExampleText")
private String exampleText;
#JsonProperty("SelectedIntentName")
private String selectedIntentName;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonProperty("EntityLabels")
public List<EntityLabel> getEntityLabels() {
return entityLabels;
}
#JsonProperty("EntityLabels")
public void setEntityLabels(List<EntityLabel> entityLabels) {
this.entityLabels = entityLabels;
}
#JsonProperty("ExampleText")
public String getExampleText() {
return exampleText;
}
#JsonProperty("ExampleText")
public void setExampleText(String exampleText) {
this.exampleText = exampleText;
}
#JsonProperty("SelectedIntentName")
public String getSelectedIntentName() {
return selectedIntentName;
}
#JsonProperty("SelectedIntentName")
public void setSelectedIntentName(String selectedIntentName) {
this.selectedIntentName = selectedIntentName;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
EntityLabel.java
package com.createjson;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({ "StartToken", "EntityType", "EndToken" })
public class EntityLabel {
#JsonProperty("StartToken")
private int startToken;
#JsonProperty("EntityType")
private String entityType;
#JsonProperty("EndToken")
private int endToken;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonProperty("StartToken")
public int getStartToken() {
return startToken;
}
#JsonProperty("StartToken")
public void setStartToken(int startToken) {
this.startToken = startToken;
}
#JsonProperty("EntityType")
public String getEntityType() {
return entityType;
}
#JsonProperty("EntityType")
public void setEntityType(String entityType) {
this.entityType = entityType;
}
#JsonProperty("EndToken")
public int getEndToken() {
return endToken;
}
#JsonProperty("EndToken")
public void setEndToken(int endToken) {
this.endToken = endToken;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
Main Class
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.config.ConfigDetails;
import com.createjson.EntityLabel;
import com.createjson.Jsoncreator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class dummy {
public static void main(String[] args) throws JsonProcessingException {
Jsoncreator jsoncreator = null;
EntityLabel label;
List<EntityLabel> entityLabelList;
ObjectMapper objectMapper;
List<String> matchList;
String[] lines = { "What is (Jim)'s gift (limit)? <=> Personname <=> Amount::Spent",
"What is (John)'s gift (limit)? <=> Personname <=> Amount::Spent" };
// check if the text has entities
for (String line : lines) {
entityLabelList = new ArrayList<EntityLabel>();
if (line.contains("<=>")) {
String[] example_split = line.split("<=>", 2);
// System.out.println("String is " + example_split[1]);
if (example_split[0].length() > 1) {
String[] example_entity = example_split[1].split("<=>");
int entities_count = 0;
int startPosition;
int endPosition = 0;
matchList = new ArrayList<>();
Pattern regex = Pattern.compile("\\((.*?)\\)");
Matcher regexMatcher = regex.matcher(line);
jsoncreator = new Jsoncreator();
while (regexMatcher.find()) {
startPosition = regexMatcher.start() + 1;
endPosition = regexMatcher.end() - 1;
matchList.add(regexMatcher.group(1));
label = new EntityLabel();
label.setStartToken(startPosition);
label.setEntityType(example_entity[entities_count].toString());
label.setEndToken(endPosition);
entityLabelList.add(label);
objectMapper = new ObjectMapper();
TestCasesString = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(label);
jsoncreator.setEntityLabels(entityLabelList);
entities_count++;
}
}
}
objectMapper = new ObjectMapper();
System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsoncreator));
}
}
}
when I run this program, there are two objects created, but I want a songle object created.
My Current O/P
{
"EntityLabels" : [ {
"StartToken" : 9,
"EntityType" : " Personname ",
"EndToken" : 12
}, {
"StartToken" : 22,
"EntityType" : " Amount::Spent",
"EndToken" : 27
} ]
}
{
"EntityLabels" : [ {
"StartToken" : 9,
"EntityType" : " Personname ",
"EndToken" : 13
}, {
"StartToken" : 23,
"EntityType" : " Amount::Spent",
"EndToken" : 28
} ]
}
My Expected O/P
[{
"EntityLabels" : [ {
"StartToken" : 9,
"EntityType" : " Personname ",
"EndToken" : 12
}, {
"StartToken" : 22,
"EntityType" : " Amount::Spent",
"EndToken" : 27
} ]
},
{
"EntityLabels" : [ {
"StartToken" : 9,
"EntityType" : " Personname ",
"EndToken" : 13
}, {
"StartToken" : 23,
"EntityType" : " Amount::Spent",
"EndToken" : 28
} ]
}]
please let me know how can I do this.
Thanks
If you want an array you need to serialise a list, the same way you are already doing with entityLabels. Every jsoncreator object is going to create a json representation for that instance, just need to save them in a list and serialise it.
Something like:
public class dummy {
public static void main(String[] args) throws JsonProcessingException {
List<Jsoncreator> objectsToSerialise = new ArrayList<>();
... your code
// check if the text has entities
for (String line : lines) {
... your code
objectsToSerialise.add(jsonCreator);
}
objectMapper = new ObjectMapper();
System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectsToSerialise));
}
}
Hope you get the idea.
Jackson – Unmarshall to Collection/Array

Categories

Resources