Creating an organized Java library - java

I want to create a library(Jar file) in Java which would contain all my methods for the database we use. There are about 60 methods in there so I would like to make it more organized. I would like to call the methods like the example provided below.
db.accounts.add(username, password); or db.accounts().add(username, password);
db.names.delete(name); or db.names().delete(name);
What is the best way of doing this in Java?

You could save yourself a lot of trouble and write a generic DAO:
package persistence;
public interface GenericDao<K, V> {
V find(K id);
List<V> find();
K save(V value);
void update(V value);
void delete(V value);
}
I'd forget about writing your own persistence classes and use a proven solution, like Spring JDBC template.
This problem has been solved many times, many ways. What do you hope to do to improve upon what exists? How will you justify the added expense of developing, testing, and maintaining this functionality?

Here some snapshot of my custom library for connect to database:
PostgreConnection.java
public class PostgreConnection {
private static Connection conn;
public Connection makeConnection(String url, String db, String username, String password) {
if (conn == null) {
try {
Class.forName(Constants.POSTGRES_DRIVER);
conn = DriverManager.getConnection(Constants.POSTGRES_URL + url + "/" + db, username, password);
} catch (SQLException | ClassNotFoundException ex) {
Logger.getLogger(PostgreConnection.class.getName()).log(Level.SEVERE, null, ex);
}
}
return conn;
}
}
Constants.java
public class Constants {
public static String POSTGRES_URL = "jdbc:postgresql://";
public static String POSTGRES_DRIVER = "org.postgresql.Driver";
}
In org.ert.model you can store all the Model that you need based on the tables of your database.
NotifyCharts.java
public class NotifyCharts {
private Integer Id;
private String revName;
private Date importDate;
private Integer pages;
private Boolean status;
public Integer getId() {
return Id;
}
public void setId(Integer Id) {
this.Id = Id;
}
public Date getImportDate() {
return importDate;
}
public void setImportDate(Date importDate) {
this.importDate = importDate;
}
public Integer getPages() {
return pages;
}
public void setPages(Integer pages) {
this.pages = pages;
}
public String getRevName() {
return revName;
}
public void setRevName(String revName) {
this.revName = revName;
}
public Boolean isStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
}
SQLQuery is an abstract class for some basic method such as insert, update, delete, etc.
SQLQuery.java
public abstract class SQLQuery<T> {
protected void makeStatement(String url, String db, String username, String password) {
PostgreConnection connect = new PostgreConnection();
Connection con = connect.makeConnection(url, db, username, password);
try {
state = (Statement) con.createStatement();
} catch (SQLException ex) {
Logger.getLogger(SQLQuery.class.getName()).log(Level.SEVERE, null, ex);
}
}
public String arrayBuilder(Object[] obj, boolean val) {
StringBuilder arr = new StringBuilder();
arr.append("(");
for (int i = 0; i < obj.length; i++) {
if (i < obj.length - 1) {
if (val) {
arr.append("'");
}
arr.append(obj[i]);
if (val) {
arr.append("'");
}
arr.append(", ");
} else {
if (val) {
arr.append("'");
}
arr.append(obj[i]);
if (val) {
arr.append("'");
}
}
}
arr.append(")");
return arr.toString();
}
public int insertRecord() throws SQLException {
StringBuilder query = new StringBuilder();
query.append("INSERT INTO ").append(tableName).append(arrayBuilder(columns, false)).append(" VALUES ").append(arrayBuilder(values, true));
return state.executeUpdate(query.toString());
}
public ResultSet getAll() throws SQLException {
StringBuilder query = new StringBuilder();
query.append("SELECT * FROM ").append(tableName);
rSet = state.executeQuery(query.toString());
return rSet;
}
public abstract void setColsAndVals(T t);
}
NotifyChartsSQL.java is implementation of the abstract class, org.ert.sql.impl is package to store all your implementation that you need.
NotifyChartsSQL.java
public class NotifyChartsSQL extends SQLQuery<NotifyCharts> {
public NotifyChartsSQL(String url, String db, String username, String password, NotifyCharts notify) {
makeStatement(url, db, username, password);
setColsAndVals(notify);
}
#Override
public final void setColsAndVals(NotifyCharts notify) {
Map<String, Object> objects = new HashMap<>();
String[] columns;
Object[] values;
if(notify.getId() != null)
objects.put("id", notify.getId());
if(notify.getRevName() != null)
objects.put("rev_name", notify.getRevName());
if(notify.getImportDate() != null)
objects.put("import_date", notify.getImportDate());
if(notify.getPages() != null)
objects.put("pages", notify.getPages());
objects.put("status", notify.isStatus());
columns = Arrays.copyOf(objects.keySet().toArray(), objects.size(), String[].class);
values = objects.values().toArray();
setColumns(columns);
setValues(values);
setTableName("notify_charts");
}
}
And last is the test package that test your custom library to make sure that everything is ok.
TestMain.java
public class TestMain {
public static void main(String[] args) {
NotifyCharts notify = new NotifyCharts();
try {
notify.setRevName("Test456");
notify.setImportDate(new Date());
notify.setPages(10);
notify.setStatus(false);
NotifyChartsSQL notCharts = new NotifyChartsSQL("localhost:5432", "charts", "username", "password", notify);
int status = notCharts.insertRecord();
if (status == 1) {
System.out.println("Success Insert");
} else {
System.out.println("Failed Insert");
}
} catch (SQLException ex) {
Logger.getLogger(TestMain.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
I suggest if you want to make this custom library if you using manual JDBC and not using ORM such as Hibernate. Because in Hibernate is already provide all the methods that you need except do you want to add some special method you can do like duffymo said before. This idea of custom library is come from the DAO and the Hibernate structure.
Thanks for read it, and please learn some Design Pattern in Java if you want to make some custom library that more organized.

Related

How to get enum description in mybatis when serializing to JSON String

Question is how to get enum description in mybatis when serializing to JSON String
mybatis works fine to get an enum property and it also works fine to get description value by Model.DocFlowEnum.getStateName()
But how to get the description value this is a draft instead of ordinary value Draft when serializing to JSON String?
Because it is a list, I don’t want to loop to manually set the descrition value
DocFlowEnum, DocFlowEnumTypeHandler ,Model
Here is the enum with description
public enum DocFlowEnum{
Draft(0, "this is a draft"),
ToProcess(1, "this is to process"),
InProcess(2, "this is in process"),
private static final Map<Integer, DocFlowEnum> byState = new HashMap<>();
static {
for (DocFlowEnum e : DocFlowEnum.values()) {
if (byState.put(e.getState(), e) != null) {
throw new IllegalArgumentException("duplicate state: " + e.getState());
}
}
}
public static DocFlowEnum getByState(Integer state) {
return byState.get(state);
}
// original code follows
private final String stateName;
private final Integer state;
DocFlowEnum(Integer state, String stateName) {
this.state = state;
this.stateName = stateName;
}
public Integer getState() {
return state;
}
public String getStateName() {
return stateName;
}
}
here is the TypeHandler for mybatis
#MappedJdbcTypes(JdbcType.INTEGER)
#MappedTypes(value = DocFlowEnum.class)
public class DocFlowEnumTypeHandler extends BaseTypeHandler<DocFlowEnum> {
#Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, DocFlowEnum userStateEnum, JdbcType jdbcType) throws SQLException {
preparedStatement.setInt(i,userStateEnum.getState());
}
#Override
public DocFlowEnum getNullableResult(ResultSet resultSet, String s) throws SQLException {
int code =resultSet.getInt(s);
if(code>=0&&code<=5){
return DocFlowEnum.getByState(code);
}
return null;
}
#Override
public DocFlowEnum getNullableResult(ResultSet resultSet, int i) throws SQLException {
int code = resultSet.getInt(i);
if(code>=0&&code<=5){
return DocFlowEnum.getByState(code);
}
return null;
}
#Override
public DocFlowEnum getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
int code = callableStatement.getInt(i);
if(code>=0&&code<=5){
return DocFlowEnum.getByState(code);
}
return null;
}
}
Here is the Model
#Data
public class Document{
private DocFlowEnum stateEnum;
}
Thank you so much to everyone who helped.
OK, after 30minutes, I find the solution. so easy.
#JsonValue
public String getStateName() {
return stateName;
}
Maybe this can help others.

Realm does not save attributes, object is not managed although copied to Realm

I have an issue with realm. I receive a custom object from an API. I assign this object to a POJO object using retrofit. Within this object I have an ArrayList of the ToDoItemobject which extends RealmObject.
I receive the data correctly with all attributes, everything gets correctly assigned. I run it through my synchronization algorithm and save it to realm in a writing transaction. But when retrieving the data after realm.commit(); the attributes of the objects are all 0 or null.
The method isManaged()is always false, even after the writing transaction, which I don't understand because in the official documentation is states that a POJO can be converted to a managed object using the copyToRealm method.
I already tried a number of things: creating the GetItemResponseClass as RealmObject, but not possible since it has to extend JSONObject to correctly receive the data from the API. I also tried to write the whole list directly to realm but the result was the same.
As a side note, it can be that my method syncPendingLists has some logic errors, but I couldn't debug it yet, since the attributes were always o and null. Thanks for any help.
Here my code from the Activity:
public class MainActivity extends AppCompatActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Realm.init(this);
RealmConfiguration config = new RealmConfiguration.Builder().name("myrealm.realm").build();
Realm.setDefaultConfiguration(config);
realm = Realm.getDefaultInstance();
RealmResults<Counter> counterList = realm.where(Counter.class).findAll();
//setting up counterObject
if (counterList.isEmpty()) {
counterObject = new Counter();
COUNTER = counterObject.getCounter();
} else {
counterObject = counterList.get(0);
COUNTER = counterObject.getCounter();
}
initializeLists();
//Adding the Fragment
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment_container, new DoneListFragment(), "DoneListFragment");
ft.add(R.id.fragment_container, new PendingListFragment(), "PendingListFragment");
ft.commit();
RetrofitClient retrofitClient = new RetrofitClient();
Retrofit retrofit = retrofitClient.getClient();
mAPIInterface = retrofit.create(ToDoistAPIInterface.class);
}
public void getRemoteItems() {
final ArrayList<ToDoItem> onlineItems = new ArrayList<ToDoItem>();
JSONArray array = new JSONArray();
array.put("items");
String auxMessage = array.toString();
mAPIInterface.getItems(RetrofitClient.TOKEN, "*", auxMessage).enqueue(new Callback<GetItemsResponseClass>() {
#Override
public void onResponse(Call<GetItemsResponseClass> call, Response<GetItemsResponseClass> response) {
GetItemsResponseClass itemsResponseClass = new GetItemsResponseClass();
itemsResponseClass = response.body();
remoteItemsList = itemsResponseClass.getItems();
boolean test = remoteItemsList.get(0).isManaged(); //returns false
boolean test1 = remoteItemsList.get(0).isValid(); //returns true refers to singleton RealmObject
syncPendingLists(pendingItemList, remoteItemsList);
}
#Override
public void onFailure(Call<GetItemsResponseClass> call, Throwable t) {
Snackbar.make(floatingButton, "Ups - Couldn't sync items, next time, I promise", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
}
private void initializeLists() {
RealmResults<ToDoItem> realmToDoItemPendingList = realm.where(ToDoItem.class).equalTo("checkedOffline", false).findAll();
initializingArrayListFromDB(realmToDoItemPendingList, pendingItemList);
RealmResults<ToDoItem> realmToDoItemDoneList = realm.where(ToDoItem.class).equalTo("checkedOffline", true).findAll();
initializingArrayListFromDB(realmToDoItemDoneList, doneItemList);
}
private void initializingArrayListFromDB(RealmResults<ToDoItem> realmToDoItemPendingList, ArrayList<ToDoItem> arrayList) {
int h;
for (h = 0; h < realmToDoItemPendingList.size(); h++) {
arrayList.add(realmToDoItemPendingList.get(h));
}
}
public void syncPendingLists(ArrayList<ToDoItem> offlinePendingList, ArrayList<ToDoItem> onlinePendingList) {
//is my sync algorithm, the important part is the for loop at the end of this method
boolean hasMatch = false;
boolean itemChanged = false;
Date offlineDate = null;
Date onlineDate = null;
if (!offlinePendingList.isEmpty()) {
for (ToDoItem item1 : offlinePendingList) {
if (item1.getId() < 10000) {
try {
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else {
for (int i = 0; i < onlinePendingList.size(); i++) {
if (item1.getId() == onlinePendingList.get(i).getId()) {
hasMatch = true;
onlinePendingList.remove(onlinePendingList.get(i));
//Compare Fields
if (!item1.getContent().equals(onlinePendingList.get(i).getContent())) {
itemChanged = true;
}
if (item1.getPriority() != onlinePendingList.get(i).getPriority()) {
itemChanged = true;
}
if (!item1.getDate_string().equals(onlinePendingList.get(i).getDate_string())) {
itemChanged = true;
}
if (itemChanged == true) {
//Format edit dates to date
DateFormat format = new SimpleDateFormat("dd/MM/yyyy", Locale.ENGLISH);
try {
offlineDate = format.parse(item1.getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
try {
onlineDate = format.parse(onlinePendingList.get(i).getDateAdded());
} catch (ParseException e) {
e.printStackTrace();
}
//compare dates to see which was last edited
if (offlineDate.compareTo(onlineDate) > 0) {
try {
deleteRemoteItem(onlinePendingList.get(i), "item_delete");
createNewRemoteItem(item1);
} catch (JSONException e) {
e.printStackTrace();
}
} else if (offlineDate.compareTo(onlineDate) < 0) {
addOrUpdateToDB(item1);
}
}
}
if (!hasMatch) {
deleteObjectFromDB(item1);
}
}
}
}
}
for (ToDoItem onlineItem1 : onlinePendingList) {
boolean isManaged1 = onlineItem1.isManaged(); //returns false, which is ok since it is not yet in the realm db
onlineItem1.setLocalId(counterObject.getCounter());
addOrUpdateToDB(onlineItem1);
boolean asdf = onlineItem1.isManaged(); //it returns false, but it should return true
incrementCounter(counterObject);
}
initializeLists();
getPendingListFragment().refreshFragment();
}
private void addOrUpdateToDB(ToDoItem newItem) {
boolean test2= newItem.isManaged(); //returns false
realm.beginTransaction();
realm.copyToRealmOrUpdate(newItem);
//realm.copyToRealm(newItem); //I tried this method as well, but no difference
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and here is the problem, it should return true, shouldn't it?
assignValuesToToDoItem(itemWithValues, newItem);
saveCounterToDB(counterObject);
}
}
Here my class code of ToDoItem:
public class ToDoItem extends RealmObject implements Parcelable {
public static final Creator<ToDoItem> CREATOR = new Creator<ToDoItem>() {
#Override
public ToDoItem createFromParcel(Parcel in) {
return new ToDoItem(in);
}
#Override
public ToDoItem[] newArray(int size) {
return new ToDoItem[size];
}
};
#PrimaryKey
private long localId;
private String content;
private boolean checkedOffline = false;
private int priority;
private String date_string;
private String temp_id;
private long id;
private String date_added;
public ToDoItem(String name) {
this.content = name;
}
public ToDoItem() {
}
protected ToDoItem(Parcel in) {
localId = in.readLong();
content = in.readString();
checkedOffline = in.readByte() != 0;
priority = in.readInt();
date_string = in.readString();
temp_id = in.readString();
id = in.readLong();
date_added=in.readString();
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean isCheckedOffline() {
return checkedOffline;
}
public void setCheckedOffline(boolean checkedOffline) {
this.checkedOffline = checkedOffline;
}
public Long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public void setRemote_id(Long remote_id) {
this.id = remote_id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isDone() {
return checkedOffline;
}
public String getDate_string() {
return date_string;
}
public void setDate_string(String date_string) {
this.date_string = date_string;
}
public long getLocalId() {
return this.localId;
}
public void setLocalId(long i) {
this.localId = i;
}
public String getTemp_id() {
return temp_id;
}
public void setTemp_id(String temp_id) {
this.temp_id = temp_id;
}
public String getDateAdded() {
return date_added;
}
public void setDateAdded(String dateAdded) {
this.date_added = dateAdded;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(localId);
dest.writeString(content);
dest.writeByte((byte) (checkedOffline ? 1 : 0));
dest.writeInt((priority));
dest.writeString(date_string);
dest.writeString(temp_id);
dest.writeLong(id);
dest.writeString(date_added);
}
#Override
public String toString() {
return "localId: " + localId + "; content: " + content;
}
}
And here the code for the GetItemsResponseClass:
public class GetItemsResponseClass extends JSONObject {
private String sync_token;
#SerializedName("temp_id_mapping")
private HashMap<String, Long> temp_id_mapping;
private boolean full_sync;
#SerializedName("items")
private ArrayList<ToDoItem> items;
public GetItemsResponseClass(){
}
public String getSync_token() {
return sync_token;
}
public void setSync_token(String sync_token) {
this.sync_token = sync_token;
}
public HashMap<String, Long> getTemp_id_mapping() {
return temp_id_mapping;
}
public void setTemp_id_mapping(HashMap<String, Long> temp_id_mapping) {
this.temp_id_mapping = temp_id_mapping;
}
public boolean isFull_sync() {
return full_sync;
}
public void setFull_sync(boolean full_sync) {
this.full_sync = full_sync;
}
public ArrayList<ToDoItem> getItems() {
return items;
}
public void setItems(ArrayList<ToDoItem> items) {
this.items = items;
}
}
EDIT: Apparently it is a desired behavior that the object does not get saved with its attributes. Consequently to assign the values you have to use getters and setters. I added the following method, however even when debugging with a watch, as stated in the official documentation the values do not get assigned:
private void assignValuesToToDoItem(ToDoItem itemWithValues, ToDoItem newItem) {
realm.beginTransaction();
newItem.setContent(itemWithValues.getContent()); //the content variable stays null
newItem.setCheckedOffline(itemWithValues.isDone()); //stays false
newItem.setPriority(itemWithValues.getPriority());
newItem.setDate_string(itemWithValues.getDate_string());
newItem.setTemp_id(itemWithValues.getTemp_id());
newItem.setId(itemWithValues.getId());
newItem.setDate_added(itemWithValues.getDate_added());
realm.commitTransaction();
}
I added this line assignValuesToToDoItem(itemWithValues, newItem); in the main activity in the method private void addOrUpdateToDB(ToDoItem newItem) {...}
Same result...
I found out 2 very important things:
The attributes are saved, however in the debugging window they appear to be 0, false or null
Even putting a Debugging Watch does not show the correct values.
To see the real value how it is in the database you have to add a Watch and put the watch directly on the getters of the object. In my case I added a Watch and typed in "newItem.getContent()". With this line I got the title of my object. However just putting a Watch with "newItem" shows "null".
copyToRealm() and copyToRealmOrUpdate() returns the managed proxy as a return value of the function you're calling.
realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns false, and it should return false
Should be
newItem = realm.copyToRealmOrUpdate(newItem);
realm.commitTransaction();
boolean test3= newItem.isManaged(); //returns true

Listeners and instance variable scope [javafx]

I cannot understand why I can't get proper values of my object inside a listener. I created an instance variable "plant" which is type of "Plant". Then in one of my methods I created a Plant object and assigned it to "plant variable". Then I set some fields of plant object like "name" and "id". Everything works fine but... I created a listener to open a new window after button click. And what is strange for me, inside this listener the program cannot see the plant object fields which I set earlier.
Here is my code:
class Plant {
private plantName;
private gridId;
public String getName() {
return plantName;
}
public void setName(String plantName) {
this.plantName = plantName;
}
public int gridId() {
return gridId;
}
public void setGridId(int gridId) {
this.gridId = gridId;
}
}
The following code presents fragment of GrowboxModel class where the fields for Plant object are setted:
public Plant selectAll(int gridId) throws SQLException {
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
String query = "SELECT * FROM plant WHERE gridId = ?";
Plant plant = new Plant();
try {
preparedStatement = connection.prepareStatement(query);
preparedStatement.setInt(1, gridId);
resultSet = preparedStatement.executeQuery();
while(resultSet.next()) {
plant.setName(resultSet.getString("name"));
plant.setGridId(resultSet.getInt("gridId"));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
preparedStatement.close();
resultSet.close();
}
return plant;
}
Below is fragment of my growboxController class:
public Plant plant;
public GrowboxModel model = new GrowboxModel();
private void growboxCellContent(VBox plantAreaVbox) {
plant = model.selectAll(Integer.parseInt(plantAreaVbox.getId()));
if (plant.getName() == null) {
plantName.setText("EMPTY " + plantAreaVbox.getId());
} else {
System.out.println("FULL" + plant.getGridId());
}
}
For now everything was great. The program the fields of plant object. But the problem is below:
public void growboxCellBehaviour(VBox plantAreaVbox) {
plantAreaVbox.setOnMouseClicked(new EventHandler<MouseEvent>() {
public void handle(MouseEvent me) {
System.out.println("NAME: " + plant.getName() + ", gridId: " + plant.getGridId());
}
});
}
It was a moment when "plant.getName()" etc. are null, although should have same name.
I know how to create a workaround but just wonder if anyone know why listener can't see these fields.
In the plant class, nothing is actually being assigned you need to actually set the variables.
class Plant {
String plantName;
int id;
public String getName() {
return plantName;
}
public void setName(String plantName1) {
plantName = plantName1;
}
public int gridId() {
return gridId;
}
public void setId(int id1) {
id = id1;
}
}

How to read elements of arraylist of a class defined in another class in java?

I am working on a project for my college.
i have two classes as "Email_info" and "contacts". In class "contacts", i made an Arraylist of type "Email_info". This class contacts is used to add data to a XML file("contacts.xml" ), and uses variables of email_info class. The problem is whenever i try to access elements of this "contacts.xml" file after unmarshalling the file, i get address as "mailwidgetaa.Email_info#12d3a4e9" instead of the actual data( which should be like, e_id- abc#gmail.com, pass- password). So how do I do get the actual data ?
below is the full code::
package mailwidgetaa;
#XmlRootElement
public class Contacts {
List<Email_info> contacList = new ArrayList<Email_info>();
#XmlElement
public List<Email_info> getContacList() {
return contacList;
}
public void setContacList(List<Email_info> contacList) {
this.contacList = contacList;
}
}
#XmlRootElement
class Email_info {
String e_id;
String u_name;
String pass;
#XmlElement
public String getE_id() {
return e_id;
}
public void setE_id(String e_id) {
this.e_id = e_id;
}
#XmlElement
public String getU_name() {
return u_name;
}
public void setU_name(String u_name) {
this.u_name = u_name;
}
#XmlElement
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
}
public class Mailwidgetaa {
public static void main(String[] args) {
contatcs con = new contacts();
con = null;
try {
JAXBContext jaxbc1 = JAXBContext.newInstance(Contacts.class);
Unmarshaller unmarsh = jaxbc1.createUnmarshaller();
con = (Contacts) unmarsh.unmarshal(new File("contacts.xml"));
} catch (Exception e) {
System.out.println("Exception " + e.getMessage());
}
Email_info ein = new Email_info();
ein.setE_id(ui);
ein.setU_name(un);
con.getContacList().add(ein);
try {
JAXBContext jaxbc = JAXBContext.newInstance(Contacts.class);
Marshaller marsh = jaxbc.createMarshaller();
marsh.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marsh.marshal(con, new File("contacts.xml"));
} catch (JAXBException e) {
System.out.println("EXCEPTION" + e.getMessage());
}
}
Iterator e= con.contacList.iterator();
while(e.hasNext()){
System.out.println(e.next());
}
}
That's because you haven't implemented toString method in your Email_Info class. Implement it like:
#Override
public String toString() {
return "e_id: " + e_id + " u_name: " + u_name + " pass: " + pass;
}

How to serialize complex Json object to QueryString for HTTP Get using Jackson?

Say that I have following objects:
public class ComplexJacksonObject extends BaseJsonObject {
public int Start;
public int Count;
public Person MyPerson;
public class Person extends BaseJsonObject {
public String Firstname;
public String Lastname;
public Address Where;
}
public class Address extends BaseJsonObject {
public String Street;
public int Number;
}
}
Obviously when I request JSON of this with Jackson I get something like:
public String toJson(ComplexJacksonObject obj) {
try {
return generateMapper().writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
// returned: {"MyPerson":{"Firstname":"First","Lastname":"Last","Where":{"Street":"Street","Number":15}},"Count":1,"Start":2}
However what I need for QueryString is that top property pairs are converted to Key=Value& format, so something like:
MyPerson={"Firstname":"First","Lastname":"Last","Where":{"Street":"Street","Number":15}}&Count=1&Start=2
Plus of course MyPerson=[This_Part_Needs_To_Be_Url_Encoded].
Is there any generic method in Jackson that would do this for me automatically? Or will I be forced to come up with something my own? Some String replacement regex? Any ideas?
[Edit] NOTE: I misunderstood the question. My answer below answers how to parse the JSON and get a Java object. You wanted to get the Key value pairs where JSON is the value for the object. The below answer will not answer that question. Sorry for the confusion.
You can fix this issue by using Jackson annotations to the java model and adding a "type" to the JSON object. You might want to research it for your purposes but here is an example from some code I have done in the past.
public class Requirement {
private String title;
private String reqId;
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
#JsonSubTypes({
#JsonSubTypes.Type(value=CountRequirementList.class, name="COUNT"),
#JsonSubTypes.Type(value=AndRequirementList.class, name="AND"),
#JsonSubTypes.Type(value=OrRequirementList.class, name="OR")
})
private List<RequirementList> fulfillments;
where the baseObject is the RequirementList and the class names are types of the requirements list.
To make things easier going back and forth from JSON, it is sometimes convenient to just add a type to the object. I have included more code below in case it helps. (note: I did not include all the getters and setters that are needed for Jackson)
public abstract class RequirementList {
private LogicType type;
private String id;
private String title;
private String description;
protected float requiredCount; //For count type subclass. Designed to be count of credits
private List<Object> fulfillments;
}
public class OrRequirementList extends RequirementList {
public OrRequirementList() {
super();
super.setType(LogicType.OR);
}
}
See my answer for this question How to serialize ANY Object into a URI?. You have to add only URL encoding to my solution. For example you can use UrlEncoder#encode(String s, String enc) method.
OK,
Here is the holder object:
public class ComplexJacksonObject extends BaseJsonObject {
public int Start;
public int Count;
public Person MyPerson;
public List<String> Strings;
public class Person extends BaseJsonObject {
public String Firstname;
public String Lastname;
public Address Where;
}
public class Address extends BaseJsonObject {
public String Street;
public int Number;
}
}
Here is how I initialize it:
ComplexJacksonObject cjo = new ComplexJacksonObject();
cjo.Count = 1;
cjo.Start = 2;
cjo.Strings = new ArrayList<String>();
cjo.Strings.add("One");
cjo.Strings.add("Two");
cjo.MyPerson = cjo.new Person();
cjo.MyPerson.Firstname = "Fi\",=[]{}rst";
cjo.MyPerson.Lastname = "Last";
cjo.MyPerson.Where = cjo.new Address();
cjo.MyPerson.Where.Street = "Street";
cjo.MyPerson.Where.Number = 15;
String result = cjo.toQueryString();
// Strings=%5B%22One%22%2C%22Two%22%5D&MyPerson=%7BFirstname%3A"Fi%5C%5C%22%2C%3D%5B%5D%7B%7Drst"%2CLastname%3A%22Last%22%2CWhere%3A%7BStreet%3A%22Street%22%2CNumber%3A15%7D%7D&Start=2&Count=1
And finally the method that makes this happen:
public String toQueryString() {
StringBuilder sb = new StringBuilder();
for (Field field : this.getClass().getDeclaredFields()) {
if (sb.length() > 0) {
sb.append("&");
}
Class cls = field.getType().getSuperclass();
// serializing my complex objects - they all inherit from BaseJsonObject class
if (cls != null && cls.equals(BaseJsonObject.class)) {
BaseJsonObject bjo = (BaseJsonObject) getFieldValue(field);
String str = toJson(bjo, true);
sb.append(field.getName()).append("=").append(Uri.encode(str));
}
// serializing lists, they are all List<T>
else if (field.getType().equals(List.class)) {
List bjo = (List) getFieldValue(field);
String val = toJson(bjo, false);
sb.append(field.getName()).append("=").append(Uri.encode(val));
}
// serializing simple fields
else {
Object bjo = getFieldValue(field);
String val = toJson(bjo, false).replaceAll("^\"|\"$", "");
sb.append(field.getName()).append("=").append(Uri.encode(val));
}
}
return sb.toString();
}
private Object getFieldValue(Field field) {
try {
return field.get(this);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
private static ObjectMapper generateMapper() {
ObjectMapper om = new ObjectMapper();
// om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
om.setDateFormat(new JacksonSimpleDateFormat());
return om;
}
public String toJson() {
try {
return generateMapper().writeValueAsString(this);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}
public String toJson(Object o, boolean noQuoteProperties) {
try {
ObjectMapper om = generateMapper();
if (noQuoteProperties) {
om.configure(com.fasterxml.jackson.core.JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
om.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
}
return om.writeValueAsString(o);
} catch (JsonProcessingException e) {
e.printStackTrace();
return null;
}
}

Categories

Resources