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.
Related
I'm trying to convert a JSON object to POJOs, and ideally I would have a list of objects (of collection's) in my cluster object. However the JSON schema doesn't use a list, it uses a map of the collection name, which aren't known and might change. Is there a way to convert this to a list of POJOs using GSON?
The JSON in question:
{
"responseHeader":{
"status":0,
"QTime":333},
"cluster":{
"collections":{
"collection1":{
"shards":{
"shard1":{
"range":"80000000-ffffffff",
"state":"active",
"replicas":{
"core_node1":{
"state":"active",
"core":"collection1",
"node_name":"127.0.1.1:8983_solr",
"base_url":"http://127.0.1.1:8983/solr",
"leader":"true"},
"core_node3":{
"state":"active",
"core":"collection1",
"node_name":"127.0.1.1:8900_solr",
"base_url":"http://127.0.1.1:8900/solr"}}},
"shard2":{
"range":"0-7fffffff",
"state":"active",
"replicas":{
"core_node2":{
"state":"active",
"core":"collection1",
"node_name":"127.0.1.1:7574_solr",
"base_url":"http://127.0.1.1:7574/solr",
"leader":"true"},
"core_node4":{
"state":"active",
"core":"collection1",
"node_name":"127.0.1.1:7500_solr",
"base_url":"http://127.0.1.1:7500/solr"}}}},
"maxShardsPerNode":"1",
"router":{"name":"compositeId"},
"replicationFactor":"1",
"znodeVersion": 11,
"autoCreated":"true",
"configName" : "my_config",
"aliases":["both_collections"]
}
},
"aliases":{ "both_collections":"collection1,collection2" },
"roles":{
"overseer":[
"127.0.1.1:8983_solr",
"127.0.1.1:7574_solr"]
},
"live_nodes":[
"127.0.1.1:7574_solr",
"127.0.1.1:7500_solr",
"127.0.1.1:8983_solr",
"127.0.1.1:8900_solr"]
}
}
I recommend you could build the POJO models, and then do the conversion after you have imported the data.
stackoverflow/model/CoreNode.java:
package stackoverflow.model;
/**
* CoreNode
*/
public class CoreNode {
private String state;
private boolean leader;
private String core;
private String node_name;
private String base_url;
public CoreNode() {
super();
}
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
public boolean getLeader() {
return this.leader;
}
public void isLeader(boolean leader) {
this.leader = leader;
}
public String getCore() {
return this.core;
}
public void setCore(String core) {
this.core = core;
}
public String getNode_name() {
return this.node_name;
}
public void setNode_name(String node_name) {
this.node_name = node_name;
}
public String getBase_url() {
return this.base_url;
}
public void setBase_url(String base_url) {
this.base_url = base_url;
}
}
stackoverflow/model/Shard.java:
package stackoverflow.model;
import java.util.Map;
/**
* Shard
*/
public class Shard {
private String range;
private String state;
private Map<String, CoreNode> replicas;
public Shard() {
super();
}
public String getRange() {
return this.range;
}
public void setRange(String range) {
this.range = range;
}
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
public List<CoreNode> getReplicas() {
return this.replicas;
}
public void setReplicas(List<CoreNode> replicas) {
this.replicas = replicas;
}
}
then in your main function, use a Map<String, Shard> structure for each collection. (and then a Map<String, Map<String, Shard>> for the genericcollections` structure)
Then, whichever map you wanted as a list, you can just do (in the case of Shards)
new ArrayList<CoreNode>(replicas.values());
You might use a TypeAdapter to have your object converted to a list of objects, or just get all objects inside cluster into a JsonArray and then parse it to a List<Collection>, something like this:
JsonArray jsonArr = new JsonArray();
JsonObject fullObj = new GsonBuilder().create().fromJson(jsonStr, JsonObject.class);
fullObj.getAsJsonObject("cluster")
.entrySet()
.forEach(col -> jsonArr.add(col.getValue()));
List<Collection> collections = gson.fromJson(jsonArr.toString(), Collection.class);
I have this class that implements Cloneable. I only need a shallow copy here. Can anyone point to what is wrong with the java compliance here.
public class EventSystem implements Cloneable{
private String enrollmentId;
private String requestId;
private String tokenId;
private Date eventAt;
private Date loggedAt;
private String appCardId;
private String fieldKey;
private String fieldValue;
private String trsDimCardIssuerId;
private String trsDimCardProductId;
private String trsDimAppEventLocationId;
private String trsDimPaymentNetworkId;
private String trsDimAppCardTypeId;
private String trsTempLogId;
public Date getEventAt() {
return eventAt;
}
public void setEventAt(Date eventAt) {
this.eventAt = eventAt;
}
public Date getLoggedAt() {
return loggedAt;
}
public void setLoggedAt(Date loggedAt) {
this.loggedAt = loggedAt;
}
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public String getEnrollmentId() {
return enrollmentId;
}
public void setEnrollmentId(String enrollemntId) {
this.enrollmentId = enrollemntId;
}
public String getTokenId() {
return tokenId;
}
public void setTokenId(String tokenId) {
this.tokenId = tokenId;
}
public String getTrsDimCardIssuerId() {
return trsDimCardIssuerId;
}
public void setTrsDimCardIssuerId(String trsDimCardIssuerId) {
this.trsDimCardIssuerId = trsDimCardIssuerId;
}
public String getTrsDimCardProductId() {
return trsDimCardProductId;
}
public void setTrsDimCardProductId(String trsDimCardProductId) {
this.trsDimCardProductId = trsDimCardProductId;
}
public String getTrsDimAppEventLocationId() {
return trsDimAppEventLocationId;
}
public void setTrsDimAppEventLocationId(String trsDimAppEventLocationId) {
this.trsDimAppEventLocationId = trsDimAppEventLocationId;
}
public String getTrsDimPaymentNetworkId() {
return trsDimPaymentNetworkId;
}
public void setTrsDimPaymentNetworkId(String trsDimPaymentNewtorkId) {
this.trsDimPaymentNetworkId = trsDimPaymentNewtorkId;
}
public String getTrsDimAppCardTypeId() {
return trsDimAppCardTypeId;
}
public void setTrsDimAppCardTypeId(String trsDimAppCardTypeId) {
this.trsDimAppCardTypeId = trsDimAppCardTypeId;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
#Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getTrsTempLogId() {
return trsTempLogId;
}
public void setTrsTempLogId(String trsTempLogId) {
this.trsTempLogId = trsTempLogId;
}
public String getAppCardId() {
return appCardId;
}
public void setAppCardId(String appCardId) {
this.appCardId = appCardId;
}
public String getFieldKey() {
return fieldKey;
}
public void setFieldKey(String fieldKey) {
this.fieldKey = fieldKey;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
}
Is there a problem with String copy here.
Your String fields aren't a problem. Your Date fields are.
When you clone an EventSystem instance, each of its fields points to exactly the same object as source object’s corresponding field. Thus, a cloned instance’s enrollmentId field points to the same String object as the original instance’s enrollmentId.
But that’s perfectly okay. You can safely share String objects, because they’re immutable. A String object cannot be altered. You can change value of a field which holds a String, but the String object itself can never change.
However, Date objects can be changed. This means the clone is not truly independent of the source instance. They both refer to the same mutable object, so if that object is changed for just one of the two EventSystem instances, both instances will see the changes, which can lead to some insidious bugs. Consider this code:
Calendar calendar = Calendar.getInstance();
calendar.set(1969, Calendar.JULY, 20, 22, 56, 0);
Date moonLanding = calendar.getTime();
EventSystem e1 = new EventSystem();
e1.setEventAt(moonLanding);
// Prints Sun Jul 20 22:56:00 EDT 1969
System.out.println(e1.getEventAt());
EventSystem e2 = (EventSystem) e1.clone();
// Both e1 and e2 have references to the same Date object, so changes
// to that Date object are seen in both objects!
e2.getEventAt().setTime(System.currentTimeMillis());
// You might expect these to be different, since we only changed
// e2.getEventAt(), but they're the same.
System.out.println(e1.getEventAt());
System.out.println(e2.getEventAt());
One way to resolve this is to use a common object-oriented technique known as defensive copying:
public Date getEventAt() {
return (eventAt != null ? (Date) eventAt.clone() : null);
}
public void setEventAt(Date eventAt) {
this.eventAt = (eventAt != null ? (Date) eventAt.clone() : null);
}
public Date getLoggedAt() {
return (loggedAt != null ? (Date) loggedAt.clone() : null)
}
public void setLoggedAt(Date loggedAt) {
this.loggedAt = (loggedAt != null ? (Date) loggedAt.clone() : null);
}
This prevents any other classes from directly modifying the internal Date field.
Another, less safe option is to clone the Date fields in your clone method:
#Override
public Object clone() throws CloneNotSupportedException {
EventSystem newInstance = (EventSystem) super.clone();
if (newInstance.eventAt != null) {
newInstance.eventAt = (Date) newInstance.eventAt.clone();
}
if (newInstance.loggedAt != null) {
newInstance.loggedAt = (Date) newInstance.loggedAt.clone();
}
return newInstance;
}
Writing the title was a bit tricky for this question :p
This is a basic java query!
I am using google cloud and it has different methods, such as launchInstance, listInstances and terminateInstance and so on.. Here, launchInstance will return a type String as Success or Fail, listInstances will return ArrayList, and so forth.
Now, I want a generic return type, so I made a class which has data entries such as status, reason, and dataRequired which will eventually send the data that is required, i.e String or ArrayList or HashMap.
How can I achieve this functionality.
Here is sample code that I was thinking of doing:
public class ResponseHelper {
private String status;
private String reason;
private String type;
private Object data;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public void dataRequired(Object data) {
switch(getType()) {
case "ArrayList": this.data=(ArrayList<String>)data;
}
}
}
If you need a Generic return type of any object in Java, just return Object as the type.(Instead of creating a separate new class for it) Then you can check which object it is and do your stuff. Below is a simple program that you can get an idea out of it
public class GenericReturn {
public static void main(String[] args) {
Object output = returnMeSomething(2);
System.out.println(output.getClass().getSimpleName());
output = returnMeSomething(1);
System.out.println(output.getClass().getSimpleName());
output = returnMeSomething(0);
System.out.println(output.getClass().getSimpleName());
}
/** This can return any Object you want as it has Object as return type*/
public static Object returnMeSomething(int num) {
if (num == 1) {
return "Test";
}
else if (num == 2) {
return new HashMap();
}
return new ArrayList();
}
}
This output as below
HashMap
String
ArrayList
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.
I have a method that return an object of a class.The object sets the properties of class and returns.
I have to traverse the object and get the value of the properties which the object has set before.
I tried to use for-each loop,iterator but failed to traverse.
Can someone please help me to get through this.Thanks in advance.
code:
public class ConsumerTool {
public MessageBean getMessages() {
MessageBean msgBean = new MessageBean();
msgBean.setAtmId(atmId.trim());
msgBean.setEventText(eventText.trim());
msgBean.setEventNumber(eventNumber.trim());
msgBean.setSeverity(severity.trim());
msgBean.setSubsystemID(subsystemID.trim());
msgBean.setUniqueEventID(uniqueEventID.trim());
msgBean.setTaskID(taskID.trim());
msgBean.setGenerator(generator.trim());
msgBean.setGeneratorBuildVsn(generatorBuildVsn.trim());
msgBean.setDateTime(dateTime.trim());
this.msgBean = msgBean;
return msgBean;
}
}
JavaBean class:
public class MessageBean implements java.io.Serializable {
public String dateTime;
public String severity;
public String eventText;
public String eventNumber;
public String generator;
public String generatorBuildVsn;
public String atmId;
public String uniqueEventID;
public String subsystemID;
public String taskID;
//System.out.println("dateTime2222222"+dateTime);
public String getAtmId() {
return this.atmId;
}
public void setAtmId(String n) {
this.atmId = n;
}
public String getDateTime() {
return this.dateTime;
}
public void setDateTime(String n) {
this.dateTime = n.trim();
}
public String getEventNumber() {
return this.eventNumber;
}
public void setEventNumber(String n) {
this.eventNumber = n;
}
public String getEventText() {
return this.eventText;
}
public void setEventText(String n) {
this.eventText = n;
}
public String getGenerator() {
return this.generator;
}
public void setGenerator(String n) {
this.generator = n;
}
public String getGeneratorBuildVsn() {
return this.generatorBuildVsn;
}
public void setGeneratorBuildVsn(String n) {
this.generatorBuildVsn = n;
}
public String getSeverity() {
return this.severity;
}
public void setSeverity(String n) {
this.severity = n;
}
public String getSubsystemID() {
return this.subsystemID;
}
public void setSubsystemID(String n) {
this.subsystemID = n;
}
public String getTaskID() {
return this.taskID;
}
public void setTaskID(String n) {
this.taskID = n;
}
public String getUniqueEventID() {
return this.uniqueEventID;
}
public void setUniqueEventID(String n) {
this.uniqueEventID = n;
}
}
The theme is the object sets the properties of javabean class and I have to get those values from UI.
In Jsp
<%
MessageBean consumer = msg.getMessages();
//Now here i want to iterate that consumer object
%>
As the MessagesBean seems to comply the javabeans specification, you can just use java.beans.Introspector for this.
MessageBean messageBean = consumerTool.getMessages();
// ...
BeanInfo beanInfo = Introspector.getBeanInfo(MessageBean.class);
for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
String name = property.getName();
Object value = property.getReadMethod().invoke(messageBean);
System.out.println(name + "=" + value);
}
This all is under the covers using the reflection API.
Update your edit reveals that you're intending to use this to present the data in JSP. This is then not really the right approach. Bite the bullet and specify every property separately. This way you've full control over the ordering.