Convert object containing repeated fields to JSON - java

I have two table country and city in mysql dababase and i make a query to return records like that as List<myDTO> :
1,france,1,paris
1,france,2,marseille
1,france,3,lion
....
MyDTO
public class MyDTO {
public Integer idLvl1;
public String nameLvl1;
public Integer idLvl2;
public String nameLvl2;
public MyDTO(Integer idLvl1, String nameLvl1, Integer idLvl2, String nameLvl2) {
this.idNiv1 = idLvl1;
this.nomNiv1 = nameLvl1;
this.idNiv2 = idLvl2;
this.nomNiv2 = nameLvl2;
}
How can i convert it to json object to avoid the repeating country :
[
{"idNiv1" :1,"nameLvl1":"France","cities":[{"idNiv2":1,"nameLvl2":"paris"}]}
{"idNiv1" :1,"nameLvl1":"France","cities":[{"idNiv2":2,"nameLvl2":"marseille"}]}
{"idNiv1" :1,"nameLvl1":"France","cities":[{"idNiv2":3,"nameLvl2":"lion"}]}
....
]
to
[
{
"idNiv1" :1,
"nameLvl1":"France",
"cities":[
{ "idNiv2":1,"nameLvl2":"paris" } ,
{ "idNiv2":2,"nameLvl2":"marseille" } ,
{ "idNiv2":3,"nameLvl2":"lion" }
]
}
....
]

You can use Google's Gson in this case :
public String getJSONFromResultSet(ResultSet rs, String key) {
Map json = new HashMap();
List list = new ArrayList();
if (rs != null) {
try {
ResultSetMetaData mData = rs.getMetaData();
while (rs.next()) {
Map<String, Object> columns = new HashMap<String, Object>();
for (int columnIndex = 1; columnIndex <= mData.getColumnCount(); columnIndex++) {
if (rs.getString(mData.getColumnName(columnIndex)) != null) {
columns.put(mData.getColumnLabel(columnIndex),
rs.getString(mData.getColumnName(columnIndex)));
} else {
columns.put(mData.getColumnLabel(columnIndex), "");
}
}
list.add(columns);
}
} catch (SQLException e) {
e.printStackTrace();
}
json.put(key, list);
}
return new Gson().toJson(json);
}
Update:
You can call getJSONFromResultSet method like below :
Connection con = DBConnectionClass.myConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM Customer");
//as an example consider a table named Customer in your DB.
ResultSet rs = ps.executeQuery();
System.out.println(getJSONFromResultSet(rs, "customer"));

Create additional classes for country and city. Transform the flat structure to nested structure of country and cities as shown below:
public class Country {
Integer idLvl1;
String nameLvl1;
public Country(Integer idLvl1, String nameLvl1) {
}
List<City> cities;
}
public class City {
Integer idLvl2;
String nameLvl2;
public City(Integer idLvl2, String nameLvl2) {
}
}
public class MyDTOConverter {
public static Collection<Country> covert(List<MyDTO> dtos){
Map<Integer, Country> countries = new LinkedHashMap<Integer, Country>();
for (MyDTO myDTO : dtos) {
//First adding the country if it doesn't exist
if (!countries.containsKey(myDTO.idLvl1)){
countries.put(myDTO.idLvl1, new Country(myDTO.idLvl1, myDTO.nameLvl1));
}
//Adding city in the existing country.
countries.get(myDTO.idLvl1).cities.add(new City(myDTO.idLvl2, myDTO.nameLvl2));
}
return countries.values();
}
}
The final Collection of Country will result is the desired JSON.

You can write Wrapper DTO on top of Your MyDTO and then use any available json libraries like Google's Gson to convert to required JSON format.
Regards,
Sakumar

Related

How to process multi-row result in a custom way?

For now I have method body of which looks like this:
jdbcTemplate.query(queryJoiningTwoTables, (rs, rowNum) -> {
final long id= rs.getLong("id");
MyObject obj = jobStatusBunchMap.get(id);
if (obj== null) {
OffsetDateTime offsetDateTime = rs.getObject("creation_timestamp", OffsetDateTime.class);
...
obj = new MyObject (offsetDateTime ...);
map.put(id, obj );
}
String jobId = rs.getString("job_id");
obj.getJobIds().add(jobId);
return null;
});
return map.values();
Looks like I use API in improper way.
Is there better method to achieve the same ?
P.S.
I tried to use jdbcTemplate#queryForRowSet but at this case rs.getObject("creation_timestamp", OffsetDateTime.class) throws exception that it is not supported operation.
There are many options to map the results using jdbcTemplate, including yours.
Maybe this will help you to understand it better:
public List<Action> findAllActions() {
final String selectStatement = "SELECT id,name FROM Actions"; // or your query
try {
return jdbcTemplate.query(selectStatement,(resultSet, rowNum) -> {
int actionId = resultSet.getInt("id");
String actionName = resultSet.getString("name");
Action action = new Action();
action.setId(actionId);
action.setName(actionName);
return action;
});
} catch (EmptyResultDataAccessException e) {
LOGGER.error("Get all actions - empty set", e);
return Collections.emptyList();
}
}
Without lambda expressions you could use jdbcTemplate query like this:
public List<Action> findAllActions() {
final String selectStatement = "SELECT id,name FROM Actions"; // or your query
try {
return jdbcTemplate.query(selectStatement, getActionRowMapper());
} catch (EmptyResultDataAccessException e) {
LOGGER.error("Get all actions - empty set", e);
return Collections.emptyList();
}
}
private RowMapper<Action> getActionRowMapper() {
return (resultSet, rowNum) -> {
int actionId = resultSet.getInt("id");
String actionName = resultSet.getString("name");
return action;
};
}
As you can see, the second parameter of jdbcTemplate.query method takes a RowMapper<Action> type but is hidden using lambdas expressions. This option is "restricting" you from making anything else besides mapping the resultSet for every row and return the result. The final result will be eventually a List of actions.
The second option is using a ResultSetExtractor which will let you to loop through the result set and gives you more flexibility. The query will be the same, just the second parameter of jdbcTemplate.query method will be changed. And for this, I would personally implement the ResultSetExtractor and override the extractData method, or you can do the same as above if you don't need anything else just to map the results
public List<Group> findGroups() {
final String selectStatement = "SELECT stud.id, stud.name, gr.id, gr.name FROM student stud INNER JOIN group gr ON gr.id=stud.group_id ORDER BY stud.id"; // or your query
try {
return jdbcTemplate.query(selectStatement, new GroupExtractor() );
} catch (EmptyResultDataAccessException e) {
LOGGER.error("Get all groups - empty set", e);
return Collections.emptyList();
}
}
public class GroupExtractor implements ResultSetExtractor<List<Group>> {
#Override
public List<Group> extractData(ResultSet resultSet) {
Map<Group, List<Student>> studentsGroup= new HashMap<>();
List<Group> groups = new ArrayList<>();
try {
while (resultSet.next()) {
int studentId = resultSet.getInt("stud.id");
String studentName = resultSet.getString("stud.name");
int groupId = resultSet.getInt("gr.id");
String groupName = resultSet.getString("gr.name");
Group group = createGroup(groupId, groupName);
Student student = createStudent(studentId, studentName);
studentsGroup.putIfAbsent(group, new ArrayList<>());
studentsGroup.get(group).add(student);
}
studentsGroup.forEach((group,students) ->{
group.setStudents(students);
groups.add(group);
}
return groups;
} catch (SQLException e) {
LOGGER.info("An error occured during extracting data", e);
}
return actions;
}
private Student createStudent(String studentId, String studentName)
{
Student student=new Student();
student.setId(studentId);
student.setName(studentName);
return student;
}
//idem for createGroup
}

MongoDB java driver using regex query to retrieve first two character

i want to retrieve first two character value like if i give 02-01-2017 00:05:46 i should get result like
02-01-2017 00:05:46
02-01-2017 00:05:46
02-01-2017 00:05:46
Without string SyTime_000_09_00:00
i am using jongo library and mongo drive 3.4.2
{
"_id" : ObjectId("590b70c609200535e85c6540"),
"Data" : "02-01-2017 00:05:46 SyTime_000_09_00:00 "
}
{
"_id" : ObjectId("590b70c609200535e85c6541"),
"Data" : "02-01-2017 00:05:46 DPMPow_P01_04_ 45.53 "
}
Here is what i have tried
public class DataSource {
private MongoCollection collection;
public void DataSource() {
this.collection = (new Jongo(new
MongoClient("localhost", 27017).getDB("admin"))).getCollection("test");
}
public void guarder(Object obj) {
this.collection.save(obj);
}
public Iterable consol() {
DBObject query = new BasicDBObject();
Pattern regex = Pattern.compile("02-01-2017");
query.put("Data", regex);
return (Iterable) this.collection.find(query.toString()).as(pojo.class);
}
}
here is pojo class
public class pojo {
#MongoObjectId
String _id;
String Data;
public pojo() {
}
public pojo(String Data) {
this.Data = Data;
}
public String getData() {
return Data;
}
public String getId() {
return _id;
}
}
i am using jframe Button Action GUi
private void findActionPerformed(java.awt.event.ActionEvent evt) {
try{
DefaultListModel listModel = new DefaultListModel();
DataSource ds=new DataSource();
ds.DataSource();
Iterable pojo=ds.consol();
pojo p;
int i=0;
for (Iterator it=pojo.iterator();it.hasNext();){
p = (pojo)it.next();
listModel.addElement(p.getData());
}
mdata.setModel(listModel); //jlist
}catch(Exception e){
System.out.println(e);
}
}
Result
As stated by Wiktor Stribiżew
p.getData() returns a String that is added to the listModel. Use p.getData().replaceFirst("^(\S+\s\S+).*", "$1")

How to create map of java POJO class/ Json String having primitive data?

I want to make a Map (String ,Object) like this
{AssessmentId=0, Physical_name='ram', Physical_height=20, Physical_weight=60}
from my Pojo Class - InitialAssessment
public class InitialAssessment {
private long AssessmentId;
private String physical_name;
private String physical_gender;
private int physical_height;
private float physical_weight;
// all getter And setter is Created here
}
without using any external Library like Gson etc.
You can use this approach:
public Map getMapFromPojo(InitialAssessment assessment) throws Exception {
Map<String, Object> map = new HashMap<>();
if (assessment != null) {
Method[] methods = assessment.getClass().getMethods();
for (Method method : methods) {
String name = method.getName();
if (name.startsWith("get") && !name.equalsIgnoreCase("getClass")) {
Object value = "";
try {
value = method.invoke(assessment);
map.put(name.substring(name.indexOf("get") + 3), value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
return map;
}
return null;
}
It will give you map for pojo class like this:
Output:
{AssessmentId=0, Physical_name='ram', Physical_gender='Male' , Physical_height=20, Physical_weight=60}

Hibernate mapping of lists

I want to retrieve 3 columns from DB.More than 2 or 3 rows are retrieved while querying.This is the query String query="select createdTime,receiptStatus,pointsEarned from Receipt where loyaltyId=:loyaltyId";
List x= (List) entityManager.createQuery(query).setParameter("loyaltyId",loyaltyId).getResultList();
I want to map the columns to a pojo class and pass the list(or use an object of that pojo).i created a pojo class like this
public class TransactionHistoryEntity
{
private List<String> tranStatus;
private List<String> tranDate;
private List<String> pointsEarned;
public List<String> getTranStatus() {
return tranStatus;
}
public void setTranStatus(List<String> tranStatus) {
this.tranStatus = tranStatus;
}
public List<String> getTranDate() {
return tranDate;
}
public void setTranDate(List<String> tranDate) {
this.tranDate = tranDate;
}
public List<String> getPointsEarned() {
return pointsEarned;
}
public void setPointsEarned(List<String> pointsEarned) {
this.pointsEarned = pointsEarned;
}
}
created time should be mapped to tranDate,receiptstatus to tranStatus,pointsEarned to pointsEarned.
How can i achieve this ?? is my query correct ?
Criteria cr= getCurrentSession().createCriteria(Receipt.class)
.add(Restrictions.eq("loyaltyId", loyaltyId))
.setProjection(Projections.projectionList()
.add(Projections.property("createdTime"), "createdTime")
.add(Projections.property("receiptStatus"), "receiptStatus")
.add(Projections.property("pointsEarned "), "pointsEarned "))
.setResultTransformer(Transformers.aliasToBean(Receipt.class));
List<Receipt> receiptList = cr.list();
This Criteria act as String query="select createdTime,receiptStatus,pointsEarned from Receipt where loyaltyId=:loyaltyId"; and map the return result to List<Receipt>
TransactionHistoryEntity trans = new TransactionHistoryEntity ();
List<String> tranStatus = new ArrayList<String>();
List<String> tranDate = new ArrayList<String>();
List<String> pointsEarned = new ArrayList<String>();
for(int i = 0 ; i < receiptList.size() ; i++){
tranDate.add(receiptList.get(i).getCreatedTime());
tranStatus.add(receiptList.get(i).getReceiptStatus());
pointsEarned.add(receiptList.get(i).getPointsEarned());
}
TransactionHistoryEntity.setTranStatus(tranStatus);
TransactionHistoryEntity.setTranDate(tranDate);
TransactionHistoryEntity.setPointsEarned(pointsEarned)
And this to map the return result to TransactionHistoryEntity

Converting the Database details to JSON object

I have a table with has the columns namely
recordID, recordName , titleFeild, titleIDMap, titleId, titleStartDate, titleEndDate, languageId
Now I have convert the data from above columns to the JSON object data which looks like below
{
"recordId" :10,
"recordName" : "RECORDS",
"records" : [ {
"titleField" : 1,
"titleIDMap" : null,
"titleId" : 500,
"titleStartDate" : "2013-12-22T00:00:00.000+0000",
"titleEndDate" : "2013-12-03T00:00:00.000+0000",
"languageId" : 20
}]
}
Please note that records is an array of columns ( titleFeild,titleIDMap,titleId,titleStartDate,titleEndDate,languageId)
The code so far I have developed is
List<Object[]> objList = dao.getStatus();
Integer result = null;
JSONObject jsonData = new JSONObject();
JSONArray jsonDataArray = new JSONArray();
if(objList!=null && objList.size()>10000)
{
for (Object[] nameObj : objList) {
jsonData.put("", nameObj.get(arg0) );
}
}
How do I construct the JSON Object from the columns data ?
You can easily achieve this with google-gson library. In simple terms you would have to create a couple of Pojos (with reference to another containin a list of references).
Consider RecordID and RecordName as Meta Data.
Create a pojo representing this information:
public class DbMetaPojo {
private int recordID;
private String recordName;
private List<Record> records;
public List<Record> getRecords() {
return records;
}
public void setRecords(List<Record> records) {
this.records = records;
}
public String getRecordName() {
return recordName;
}
public void setRecordName(String recordName) {
this.recordName = recordName;
}
public int getRecordID() {
return recordID;
}
public void setRecordID(int recordID) {
this.recordID = recordID;
}
}
Create another pojo with the actual Record fields:
public class Record {
public int getTitleFeild() {
return titleFeild;
}
public void setTitleFeild(int i) {
this.titleFeild = i;
}
public String getTitleIDMap() {
return titleIDMap;
}
public void setTitleIDMap(String titleIDMap) {
this.titleIDMap = titleIDMap;
}
public int getTitleId() {
return titleId;
}
public void setTitleId(int titleId) {
this.titleId = titleId;
}
public String getTitleStartDate() {
return titleStartDate;
}
public void setTitleStartDate(String titleStartDate) {
this.titleStartDate = titleStartDate;
}
public String getTitleEndDate() {
return titleEndDate;
}
public void setTitleEndDate(String titleEndDate) {
this.titleEndDate = titleEndDate;
}
public int getLanguageId() {
return languageId;
}
public void setLanguageId(int languageId) {
this.languageId = languageId;
}
private int titleFeild;
private String titleIDMap;
private int titleId;
private String titleStartDate;
private String titleEndDate;
private int languageId;
}
Now just a method to populate your POJOs with the relevant data (replace the hardcoding logic with your data retrieve):
public static void main(String... main) {
DbMetaPojo obj = new DbMetaPojo();
obj.setRecordID(10);
obj.setRecordName("RECORDS");
Record record = new Record();
record.setLanguageId(20);
record.setTitleEndDate("2013-12-22T00:00:00.000+0000");
record.setTitleFeild(1);
record.setTitleId(500);
record.setTitleIDMap("SOME NULL");
record.setTitleStartDate("2013-12-22T00:00:00.000+0000");
List<Record> list = new ArrayList<Record>();
list.add(record);
obj.setRecords(list);
Gson gson = new Gson();
String json = gson.toJson(obj);
System.out.println(json);
}
Output is your formed JSON:
{
"recordID": 10,
"recordName": "RECORDS",
"records": [
{
"titleFeild": 1,
"titleIDMap": "SOME NULL",
"titleId": 500,
"titleStartDate": "2013-12-22T00:00:00.000+0000",
"titleEndDate": "2013-12-22T00:00:00.000+0000",
"languageId": 20
}
]
}
EDIT:
To align to your code, you might want to do something like:
List<Object> objList = dao.getStatus();
List<DbMetaPojo> metaList = new ArrayList<DbMetaPojo> ();
if (objList != null && objList.size() > 10000) {
for (Object nameObj : objList) {
DbMetaPojo meta = new DbMetaPojo();
meta.setRecordID(nameObj[0]);
meta.setRecordName(nameObj[0]);
...
...
...
metaList.add(meta);
}
}
First of all what you have to do is retrieve the data from the columns of the table using your DAO and calling a Function from DAOIMPL which in turn will return the list of data(POJO probably).
Create a map like this which will contain your key value pair for example recordid and value,
recordname and value
Map<String,Object> objMap = new HashMap<String,Object>();
objMap.put("recordId", Record.getId());
objMap.put("recordName",Record.getName());
// Now here is the deal create another hashmap here whose key will be records "the key for your second array"
//Put the values in this second hashmap as instructed above and put it as a key value pair.
........
.......
.......
JSONObject JsonObject = JSONObject.fromObject(objMap);//This will create JSON object out of your hashmap.
objJSONList.add(JsonObject);
}
StringBuffer jsonBuffer = new StringBuffer();
jsonBuffer.append("{\"data\": {");
jsonBuffer.append(objJSONList.tostring());
jsonBuffer.append("}");
//jsonBuffer.append(",\"total\":"+ objJSONList.size());// TOTAL Optional
//jsonBuffer.append(",\"success\":true}");//SUCCESS message if using in callback Optional
Create an object which has your attribues. (recordID, recordName , titleFeild, titleIDMap, titleId, titleStartDate, titleEndDate, languageId)
Get data from dao and convert it to json. It will looks like what you want.
Gson gson = new Gson();
// convert java object to JSON format,
// and returned as JSON formatted string
String json = gson.toJson(obj);
I think your dao.getStatus() should return a List with Map keys and values. Your key would be column name and value would be content.
List<Map<String,Object>> objList = dao.getStatus();
if(objList!=null && objList.size()>10000){
for(Map<String,Object> row : objList) {
Iterator<String> keyList = row.keySet().iterator();
while(keyList.hasNext()){
String key = keyList.next();
jsonData.put(key, row.get(key));
}
}
}
For the records array you need to build it while iterating table columns.
Combining above code with building records array would be something like this..
String[] group = {"titleField","titleIDMap","titleId","titleStartDate","titleEndDate","languageId"};
List<String> recordGroup = Arrays.asList(group);
Map<Object, JSONArray> records = new HashMap<Object,JSONArray>();
List<Map<String,Object>> objList = dao.getStatus();
JSONObject jsonData = new JSONObject();
if(objList!=null && objList.size()>10000){
for(Map<String,Object> row : objList) {
int columnCount = 0;
Iterator<String> keyList = row.keySet().iterator();
while(keyList.hasNext()){
String key = keyList.next();
if(recordGroup.contains(key)){
Object recordId = row.get("recordId");
JSONArray recordArray = new JSONArray();
if(records.containsKey(recordId)){
recordArray = records.get(recordId);
JSONObject jsonObj = null;
if(columnCount >= recordGroup.size()){
jsonObj = new JSONObject();
recordarray.add(jsonObj);
columnCount = 0;
}
else {
jsonObj = (JSONObject) recordArray.get(recordArray.size()-1);
}
jsonObj.put(key, row.get(key));
columnCount++;
}
else {
JSONObject jsonObj = new JSONObject();
jsonObj.put(key, row.get(key));
recordArray.add(jsonObj);
records.put(recordId, recordArray);
}
jsonData.put("records", records.get(recordId));
}
else {
jsonData.put(key, row.get(key));
}
}
}
}

Categories

Resources