Java : Convert Object consisting enum to Json Object - java

I am using org.json library to convert Object to Json format. Kindly check the below code snippet.
public enum JobStatus implements Serializable{
INCOMPLETE,
INPROGRESS,
ABORTED,
COMPLETED
}
public class Job implements Serializable {
private string id;
private JobStatus status;
...
}
...
// Create Job Object
Job job = new Job("12345", JobStatus.INPROGRESS);
// Convert and print in JSON format
System.out.println(new JSONObject(job).toString());
It shows the output like this :
{"id":"12345", "status" : {}}
It shows blank and adds Curly bases. What does it mean? Is anybody gone through this problem?

First of all I highly recommend do not use this library (org.json), this is very old and unsupported (as i know) library. I suggest Jackson or Gson.
But if you really need JSONObject, you can add getter into enum:
public enum JobStatus implements Serializable{
INCOMPLETE,
INPROGRESS,
ABORTED,
COMPLETED;
public String getStatus() {
return this.name();
}
}
result of serialization:
{"id":"12345","status":{"status":"INPROGRESS"}}
As I know, JSONObject don't support correct serialization of enums which not have any additional data inside.

ObjectMapper mapper= new ObjectMapper();
new JSONObject(mapper.writeValueAsString(job));
would do the trick. Now Enums and DateTime types looks normal and is converted properly in json objects.
I came to this page as a person seeking answer and my research helped me to answer this question.

It seems JSONObject doesn't support enums. You could alter your Job class to add a getter like this:
public String getStatus() {
return status.name();
}
then, invoking new JSONObject(job).toString() produces:
{"id":"12345","status":"INPROGRESS"}

for me, i made an interface that shuold be implemented by any enum i will have to use in Json, this interface forces the enum to know the proper enum itself from a value, and also it should return a value ... so every enum.CONSTANT is mapped to a value of any type (weather a number or a String)
so when i want to put this enum in a Json Object, i ask the enum.CONSTANT to give me it's value, and when i have this value (from Json), i can request from the enum to give me the proper enum.CONSTANT mapped to this value
the interface is as follows (you can copy it as it is) :
/**
*
* this interface is intended for {#code enums} (or similar classes that needs
* to be identified by a value) who are based on a value for each constant,
* where it has the utility methods to identify the type ({#code enum} constant)
* based on the value passed, and can declare it's value in the interface as
* well
*
* #param <T>
* the type of the constants (pass the {#code enum} as a type)
* #param <V>
* the type of the value which identifies this constant
*/
public interface Valueable<T extends Valueable<T, V>, V> {
/**
* get the Type based on the passed value
*
* #param value
* the value that identifies the Type
* #return the Type
*/
T getType(V value);
/**
* get the value that identifies this type
*
* #return a value that can be used later in {#link #getType(Object)}
*/
V getValue();
}
now here is an example for a small enum implementing this interface:
public enum AreaType implements Valueable<AreaType, Integer> {
NONE(0),
AREA(1),
NEIGHBORHOOD(2);
private int value;
AreaType(int value) {
this.value = value;
}
#Override
public AreaType getType(Integer value) {
if(value == null){
// assume this is the default
return NONE;
}
for(AreaType a : values()){
if(a.value == value){ // or you can use value.equals(a.value)
return a;
}
}
// assume this is the default
return NONE;
}
#Override
public Integer getValue() {
return value;
}
}
to save this enum in a Json :
AreaType areaType = ...;
jsonObject.put(TAG,areaType.getValue());
now to get your value from a Json Object :
int areaValue = jsonObject.optInt(TAG,-1);
AreaType areaType = AreaType.NONE.getType(areaValue);
so if the areaValue is 1 for example, the AreaType will be "Area", and so on

Similar to what #Denys Denysiuk has answered. But if you want to return any value instead of String We can use like this. In below example i wanted to return value 1, or 15 instead of String
#Getter
public enum PaymentCollectionDay {
FIRST_OF_MONTH(1), FIFTEENTH_OF_MONTH(15);
PaymentCollectionDay(int day) {
this.day = day;
}
#JsonValue
final int day;
}

Related

Hazelcast get operation

Get the hazelcast value by key...
IMap<tblHeaders, HazelcastJsonValue> person = hazelcastInstance.getMap("person");
person.put(new tblHeaders("1", "ram", "0001"), new HazelcastJsonValue("{ \"name1\":\"John1\" }"));
person.put(new tblHeaders("1", "vikas", "0002"), new HazelcastJsonValue("{ \"name2\":\"John2\" }"));
person.put(new tblHeaders("1", "datrs", "0003"), new HazelcastJsonValue("{ \"name3\":\"John3\" }"));
Model Class
public class tblHeaders implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String school_id;
private String name;
private String unique_id;
Here How to get the value by passing single key...
example
HazelcastJsonValue json = person.get("school_id='0001'");
System.out.println(json.toString()); //get the value here
A few things here.
The IMap.get() method can only retrieve by a full key value; since you are providing only a partial key the get() method will not match anything.
The IMap.values() method takes a Predicate argument, and is the right method to use when trying to do a query that matches based on the partial content of the key or the full or partial content of the entry's value.
By default, a Predicate is applied against the value, but you can specify that it apply to the key by using the keyword __key (two underscores) in the attribute field of the predicate.
Since the query may (and does) match multiple items, the correct return type is a Collection of HazelcastJsonValue.
Here's the code that will do what you're trying:
Predicate schoolPredicate = Predicates.equal("__key.school_id", "1");
Collection<HazelcastJsonValue> json = person.values(schoolPredicate);
System.out.println(json); //get the value here
Giving the output
[{ "name3":"John3" }, { "name1":"John1" }, { "name2":"John2" }]

Enum inner field as parameter of Spring Data #Query statement

I have enum with inner value:
public enum Test {
A("a");
private String value;
Test(String value) {
this.value = value;
}
#Override
public String toString() {
return this.value;
}
}
And I use it as a parameter in Spring Data Cassandra #Query.
Also I added read and write converter to just for parsing "a" -> A and back.
I was expected that if I send A as parameter the query will be generated by converters to. But the query was like "... my_enum = 'A'" instead of 'a'.
I was trying to debug spring sources and found this part of code org/springframework/data/spring-data-cassandra/1.5.9.RELEASE/spring-data-cassandra-1.5.9.RELEASE-sources.jar!/org/springframework/data/cassandra/convert/MappingCassandraConverter.java:799:
// Cassandra has no default enum handling - convert it either to string
// or - if requested - to a different type
if (Enum.class.isAssignableFrom(value.getClass())) {
if (requestedTargetType != null && !requestedTargetType.isEnum()
&& getConversionService().canConvert(value.getClass(), requestedTargetType)) {
return getConversionService().convert(value, requestedTargetType);
}
return ((Enum<?>) value).name();
}
Looks like if parameter is enum - converters never be used.
How can i deal with it?
Thank you.

Java Jackson receive key with null value [duplicate]

What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
Summarizing excellent answers by Programmer Bruce and StaxMan:
Missing properties referenced by the constructor are assigned a default value as defined by Java.
You can use setter methods to differentiate between properties that are implicitly or explicitly set. Setter methods are only invoked for properties with explicit values. Setter methods can keep track of whether a property was explicitly set using a boolean flag (e.g. isValueSet).
What happens if I annotate a constructor parameter using #JsonProperty but the Json doesn't specify that property. What value does the constructor get?
For questions such as this, I like to just write a sample program and see what happens.
Following is such a sample program.
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFoo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper();
// {"name":"Fred","id":42}
String jsonInput1 = "{\"name\":\"Fred\",\"id\":42}";
Bar bar1 = mapper.readValue(jsonInput1, Bar.class);
System.out.println(bar1);
// output:
// Bar: name=Fred, id=42
// {"name":"James"}
String jsonInput2 = "{\"name\":\"James\"}";
Bar bar2 = mapper.readValue(jsonInput2, Bar.class);
System.out.println(bar2);
// output:
// Bar: name=James, id=0
// {"id":7}
String jsonInput3 = "{\"id\":7}";
Bar bar3 = mapper.readValue(jsonInput3, Bar.class);
System.out.println(bar3);
// output:
// Bar: name=null, id=7
}
}
class Bar
{
private String name = "BLANK";
private int id = -1;
Bar(#JsonProperty("name") String n, #JsonProperty("id") int i)
{
name = n;
id = i;
}
#Override
public String toString()
{
return String.format("Bar: name=%s, id=%d", name, id);
}
}
The result is that the constructor is passed the default value for the data type.
How do I differentiate between a property having a null value versus a property that is not present in the JSON?
One simple approach would be to check for a default value post deserialization processing, since if the element were present in the JSON but had a null value, then the null value would be used to replace any default value given the corresponding Java field. For example:
import org.codehaus.jackson.annotate.JsonAutoDetect.Visibility;
import org.codehaus.jackson.annotate.JsonMethod;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonFooToo
{
public static void main(String[] args) throws Exception
{
ObjectMapper mapper = new ObjectMapper().setVisibility(JsonMethod.FIELD, Visibility.ANY);
// {"name":null,"id":99}
String jsonInput1 = "{\"name\":null,\"id\":99}";
BarToo barToo1 = mapper.readValue(jsonInput1, BarToo.class);
System.out.println(barToo1);
// output:
// BarToo: name=null, id=99
// {"id":99}
String jsonInput2 = "{\"id\":99}";
BarToo barToo2 = mapper.readValue(jsonInput2, BarToo.class);
System.out.println(barToo2);
// output:
// BarToo: name=BLANK, id=99
// Interrogate barToo1 and barToo2 for
// the current value of the name field.
// If it's null, then it was null in the JSON.
// If it's BLANK, then it was missing in the JSON.
}
}
class BarToo
{
String name = "BLANK";
int id = -1;
#Override
public String toString()
{
return String.format("BarToo: name=%s, id=%d", name, id);
}
}
Another approach would be to implement a custom deserializer that checks for the required JSON elements. And yet another approach would be to log an enhancement request with the Jackson project at http://jira.codehaus.org/browse/JACKSON
In addition to constructor behavior explained in #Programmer_Bruce's answer, one way to differentiate between null value and missing value is to define a setter: setter is only called with explicit null value.
Custom setter can then set a private boolean flag ("isValueSet" or whatever) if you want to keep track of values set.
Setters have precedence over fields, in case both field and setter exist, so you can "override" behavior this way as well.
I'm thinking of using something in the style of an Option class, where a Nothing object would tell me if there is such a value or not. Has anyone done something like this with Jackson (in Java, not Scala, et al)?
(My answer might be useful to some people finding this thread via google, even if it doesn't answer OPs question)
If you are dealing with primitive types which are omittable, and you do not want to use a setter like described in the other answers (for example if you want your field to be final), you can use box objects:
public class Foo {
private final int number;
public Foo(#JsonProperty Integer number) {
if (number == null) {
this.number = 42; // some default value
} else {
this.number = number;
}
}
}
this doesn't work if the JSON actually contains null, but it can be sufficient if you know it will only contain primitives or be absent
another option is to validate the object after deserialization either manually or via frameworks such java bean validation or, if you are using spring, the spring validation support.

Mybatis No Getter Property

I'm working with Mybatis 3.2.6 and implementing a custom resulthandler. I've done this before using a simple datatype parameter and have had no problems. This time around I need to pass in several arguments... The signature I'm using is
session.select(statement, parameter, handler);
For parameter I've created a simple POJO to easily send in what I need. It is as follows:
public class DifferenceParam {
private int current;
private int compare;
private String table;
private String comparator;
/**
* Constructor excluding comparator. Will default a value of
* "code" to compare content on, e.g., <br/>
* {#code select * from a minus select * from b where a.code = b.code } <br/>
* #param table
* #param current
* #param compare
*/
public DifferenceParam(String table, int current, int compare) {
this(table, "code", current, compare);
}
/**
* Constructor providing a specific column to compare on, e.g. <br/>
* {#code select * from a minus select * from b where a.[comparator] = b.[comparator] } <br/>
* #param table
* #param comparator
* #param current
* #param compare
*/
public DifferenceParam(String table, String comparator, int current, int compare) {
this.table = table;
this.comparator = comparator;
this.current = current;
this.compare = compare;
}
/** Appropriate setters and getters to follow **/
}
The handler implementation is irrelevant at the moment, because I get an exception well in advance... The query I'm executing is:
<select id="getCodeSetModifications" parameterType="DifferenceParam" resultType="Code">
select *
from
(
select * from ${param.table} where revision_seq = #{param.current}
minus
select * from ${param.table} where revision_seq = #{param.compare}
) a, ${param.table} b
where a.${param.comparator} = b.${param.comparator}
and b.revision_seq = #{param.compare}
</select>
Here is the interface as well
public List<Code> getCodeSetModifications(#Param("param") DifferenceParam param);
The problem I'm having is that execution via a mapper e.g.,
session.getMapper(DifferenceParam.class);
works just fine, but when I invoke through a select on the session I get the following exception.
Error querying database. Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'param' in 'class com.mmm.his.cer.cerval.uidifference.map.param.DifferenceParam'
Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'param' in 'class com.mmm.his.cer.cerval.uidifference.map.param.DifferenceParam'
I've debugged as far as I can go into Mybatis, but am having no luck.
Thanks in advance...
When you use session.getMapper(DifferenceParam.class);, mybatis looks for #Param annotation and uses it's value in query.
When you invoke session.select(statement, parameter, handler);, such mapping doesn't occur.
Try to add public DifferenceParam getParam() { return this; } to DifferenceParam to workaround this.
when the MyBatis query only have one param. Don't need #{param.} reference.
because it default use the only param.
so when u use ${param.table}, it actually using #{DifferenceParam.param.table}.
because it think the ${param.} inside of the #{DifferenceParam.}

Jena custom datatype

For a GeoSPARQL test project I want to have a custom datatype set in Jena. Howerver when I try this through the example provided at the Jena website, it still doesn't work. I get the following result:
_:b0 <http://www.opengis.net/ont/geosparql#asWKT> "POINT (52.83525867111958 6.870789811954563)^^http://www.opengis.net/ont/sf#wktLiteral "^^<java:com.hp.hpl.jena.rdf.model.impl.LiteralImpl> .
And of course I don't want the java:com.hp.hpl.jena.rdf.model.impl.LiteralImpl but http://www.opengis.net/ont/sf#wktLiteral because I wan to work with GeoSPARQL. On this page they have example data that works perfectly with my triple store and spatial index. But the above data doesn't work at all with spatial indexing.
So, my question is, I do I define a custom datatype in my RDF in Jena?
The syntax is
"POINT (52.83525867111958 6.870789811954563)"^^<http://www.opengis.net/ont/sf#wktLiteral>
I just found the answer to my question after a lot of trial and error. To add a custom RDFDatatype to my RDF model I first had to create my own class which extends BaseDatetype and which I called WktLiteral, looking like this:
public class WktLiteral extends BaseDatatype {
public static final String TypeURI = "http://www.opengis.net/ont/sf#wktLiteral";
public static final String CRS84 = "<http://www.opengis.net/def/crs/OGC/1.3/CRS84>";
public static final RDFDatatype wktLiteralType = new WktLiteral();
private WktLiteral() {
super(WktLiteral.TypeURI);
}
/**
* Convert a value of this datatype out
* to lexical form.
*/
public String unparse(Object value) {
return value.toString();
}
/**
* Parse a lexical form of this datatype to a value
*/
public Object parse(String lexicalForm) {
return new TypedValue(String.format("%s %s", WktLiteral.CRS84, lexicalForm), this.getURI());
}
/**
* Compares two instances of values of the given datatype.
* This does not allow rationals to be compared to other number
* formats, Lang tag is not significant.
*
* #param value1 First value to compare
* #param value2 Second value to compare
* #return Value to determine whether both are equal.
*/
public boolean isEqual(LiteralLabel value1, LiteralLabel value2) {
return value1.getDatatype() == value2.getDatatype()
&& value1.getValue().equals(value2.getValue());
}
Where it was quite important to return a TypedLiteral in the parse() method. After which I had to do the following to add something to my RDF model:
TypeMapper.getInstance().registerDatatype(WktLiteral.wktLiteralType);
item.addLiteral(GeoSPARQL.asWKT, ResourceFactory.createTypedLiteral(geom, WktLiteral.wktLiteralType));
Where GeoSPARQL.asWKT is the predicate in the GeoSPARQL vocabulary that I generated through schemagen. geom is the geometry object as well known text and WktLiteral.wktLiteralType is an instance of the above class.
In conclusion the result was the following (notation 3):
_:b0 <http://www.w3.org/2003/01/geo/wgs84_pos#lat_long> "POINT (51.61821756986111 5.542408362751153)" .
thus exactly what I wanted... Thanks for all the input.

Categories

Resources