xStream changes order of objects in write/readObject with JSON serialization - java

We use XStream to serialize objects to JSON and vice versa.
We init xStream like this
XStream xStream = new XStream(new JettisonMappedXmlDriver(new Configuration(), false));
xStream.ignoreUnknownElements();
xStream.setMode(XStream.XPATH_RELATIVE_REFERENCES);
We have test class
public static class TestWOWithBI implements Serializable{
private static final long serialVersionUID = -4720678317857471031L;
private transient String customerNickname;
private transient String customerUuid;
private transient BigInteger discussionId;
private transient String message;
public TestWOWithBI(String customerNickname, String customerUuid, BigInteger discussionId, String message){
this.customerNickname = customerNickname;
this.customerUuid = customerUuid;
this.discussionId = discussionId;
this.message = message;
}
private final void writeObject(final ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeObject(customerNickname);
out.writeObject(customerUuid);
out.writeObject(discussionId);
out.writeObject(message);
}
private final void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException{
in.defaultReadObject();
customerNickname = (String) in.readObject();
customerUuid = (String) in.readObject();
discussionId = (BigInteger) in.readObject();
message = (String) in.readObject();
}
}
After serialization it looks like this:
{
"somethere.ObjectToJSONSerializerTest$TestWOWithBI": {
"#serialization": "custom",
"somethere.ObjectToJSONSerializerTest$TestWOWithBI": {
"default": "",
"string": ["name",
"uuid",
"message"],
"big-int": 1
}
}
}
and deserialization fails with class cast. It was on 1.3.1 and 1.4.7 versions. Looks like bug to me, but may be where is some settings?
UPD:
Seems like org.codehaus.jettison.mapped.MappedXMLStreamWriter.JSONPropertyObject#withProperty
if(old != null) {
JSONArray values;
// Convert an existing property to an array
// and append to the array
if (old instanceof JSONArray) {
values = (JSONArray)old;
} else {
values = new JSONArray();
values.put(old);
}
values.put(value);
object.put(property.getKey(), values);
} else if(getSerializedAsArrays().contains(property.getKey())) {
JSONArray values = new JSONArray();
values.put(value);
object.put(property.getKey(), values);
} else {
// Add the property directly.
object.put(property.getKey(), value);
}
It just group elements of same type.

Related

Extracting the value of an element from a JSON

I'm trying to make a test where I get some documents based on the id of the batch they belong to. More specifically, I want to check that a specific batchPublicId is in the response body. I am using okhttp for the test.
This a shorter version of the json:
{
"_embedded": {
"invoices": [
{
"type": "INVOICE",
"publicId": "27bc8426-17cf-4fe5-9278-64108ae05e4b",
"deliveryStatus": null,
"processingStatus": "INITIATED",
"batchPublicId": "0000000000000000000000001"
}
]
}
}
I'm new to json and this is how far I got with the problem:
String invoicesJsonData = response.body().string();
JSONObject invoicesJsonObject = new JSONObject(invoicesJsonData);
Assert.assertTrue(invoicesJsonObject.getJSONObject("_embedded") !=null && invoicesJsonObject.getJSONObject("_embedded").has("invoices"));
I would like to verify that batchPublicId has the value mentioned in the json. Is there a way to do this? Thank you.
String invoicesJsonData = response.body().string();
JSONObject invoicesJsonObject = new JSONObject(invoicesJsonData);
JSONObject invoicesJsonObject1 = invoicesJsonObject.getJSONObject("_embedded");
JSONArray f2=invoicesJsonObject1.getJSONArray("invoices");
for(int i=0;i<f2.length();i++){
JSONObject obj=f2.getJSONObject(i);
if(obj.get("batchPublicId")!=null){
System.out.println(obj.get("batchPublicId"));
}
You can do something like this,Which worked out for me sometimes back.
String invoicesJsonData = response.body().string();
JSONObject invoicesJsonObject = new JSONObject(invoicesJsonData);
JSONObject invoicesJsonObject = json.getJSONObject("invoicesJsonObject");
String batchPublicId = invoicesJsonObject.getString("batchPublicId");
System.out.println( "batchPublicId: " + batchPublicId );
if(batchPublicId !=null){
// do something
}
Not sure about the syntax.Giving you a hint.
you can check any keys is there in json object or not like below :
if(jsonObject1.has("batchPublicId")){
String batchPublicId = jsonObject1.optString("batchPublicId");
Log.i(getClass().getSimpleName(), "batchPublicId=" + batchPublicId);}
has method is used to find any key is there in jsonobject or not.
In my opinion, a better approach for this would be to create a POJO from this JSON string, and extract the information you need using simply the getters
For example:
Wrapper class:
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonRootName(value = "_embedded")
public class Embeded {
#JsonProperty("invoices")
private List<Invoice> invoices;
public Embeded() {}
public List<Invoice> getInvoices() {
return invoices;
}
public void setInvoices(List<Invoice> invoices) {
this.invoices = invoices;
}
}
Invoice class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Invoice {
#JsonProperty("type")
private String type;
#JsonProperty("publicId")
private String publicId;
#JsonProperty("deliveryStatus")
private String deliveryStatus;
#JsonProperty("processingStatus")
private String processingStatus;
#JsonProperty("batchPublicId")
private String batchPublicId;
public Invoice() {}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getPublicId() {
return publicId;
}
public void setPublicId(String publicId) {
this.publicId = publicId;
}
public String getDeliveryStatus() {
return deliveryStatus;
}
public void setDeliveryStatus(String deliveryStatus) {
this.deliveryStatus = deliveryStatus;
}
public String getProcessingStatus() {
return processingStatus;
}
public void setProcessingStatus(String processingStatus) {
this.processingStatus = processingStatus;
}
public String getBatchPublicId() {
return batchPublicId;
}
public void setBatchPublicId(String batchPublicId) {
this.batchPublicId = batchPublicId;
}
}
Test:
public void json_test() throws JsonParseException, JsonMappingException, IOException {
String json = "{"
+ "\"_embedded\": {"
+ "\"invoices\": ["
+ "{"
+ "\"type\": \"INVOICE\","
+ "\"publicId\": \"27bc8426-17cf-4fe5-9278-64108ae05e4b\","
+ "\"deliveryStatus\": null,"
+ "\"processingStatus\": \"INITIATED\","
+ "\"batchPublicId\": \"0000000000000000000000001\""
+ "}"
+ "]"
+ "}"
+ "}";
ObjectMapper mapper = new ObjectMapper();
mapper.configure(Feature.UNWRAP_ROOT_VALUE, true);
List<Invoice> invoices = mapper.readValue(json, Embeded.class).getInvoices();
Assert.assertTrue(StringUtils.equals(invoices.get(0).getBatchPublicId(), "0000000000000000000000001"));
}
If I understand your right, you just need to call:
Assert.assertTrue(invoicesJsonObject.getString("batchPublicId").equals("0000000000000000000000001"));"
If you want to create a test for JSON Validation, you can use the JSONAssert.
JSONAsset give the method assertEquals, that compare two json structures, strict identic or not.
final String expected_result = YOUR_EXPECTED_RESULT;
JSONAssert.assertEquals(YOUR_EXPECTED_JSON_RESULT, RESULT_FROM_RESPONSE_BODY, false);
The last boolean parameter defines if you want an strict comparation or just compare if your expected result is in result from response.

How can I use BeanUtils converter to List?

Here, the request Param string is :
firstName=jack&lastName=lily&gender=1&foods=Steak&foods=Pizza&quote=Enter+your+favorite+quote!&education=Jr.High&tOfD=Day
And Mapped class is :
public class Student {
private String firstName;
private String lastName;
private Integer gender;
private List<String> foods;
private String quote;
private String education;
private String tOfD;
getXxx()....;
setXxx()....;
}
And Now, I want to write a generic util class to convert the string to a bean.
public final class InjectUtil<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(InjectUtil.class);
public static <T> T converter2Obj(String source, Class<T> tClass) {
T t = null;
try {
t = tClass.newInstance();
if(source != null && source.length() > 0) {
String[] fields = source.split("&");
for(String field : fields) {
String[] fieldKeyValue = field.split("\\=");
String fieldKey = fieldKeyValue[0];
String fieldValue = fieldKeyValue[1];
// help
}
}
} catch(InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return t;
}
}
take care of the help, how can i use BeanUtils converter the "foods=Steak&foods=Pizza" to the List attribute.
Here is a way of doing it :
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.beanutils.BeanUtils;
public final class InjectUtil<T> {
// private static final Logger LOGGER =
// LoggerFactory.getLogger(InjectUtil.class);
public static <T> T converter2Obj(String source, Class<T> tClass) {
T t = null;
try {
t = tClass.newInstance();
Map<String, Object> params = new HashMap<String, Object>();
if (source != null && source.length() > 0) {
String[] fields = source.split("&");
for (String field : fields) {
String[] fieldKeyValue = field.split("\\=");
String fieldKey = fieldKeyValue[0];
String fieldValue = fieldKeyValue[1];
if (params.containsKey(fieldKey)) {
//the key does not exist as yet
Object keyValueRetrieved = params.get(fieldKey);
if (keyValueRetrieved instanceof String) {
//key exists , it is single value that has been added now.
//change that now to a list to add more values
ArrayList<String> values = new ArrayList<String>();
values.add(keyValueRetrieved.toString());
values.add(fieldValue);
params.put(fieldKey, values);
} else {
//key exists , it is a list already. Add more values
((ArrayList<String>) keyValueRetrieved).add(fieldValue);
}
} else {
params.put(fieldKey, fieldValue);
}
}
}
BeanUtils.populate(t, params);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("--------------------------------------------");
System.out.println(t.toString());
System.out.println("--------------------------------------------");
return t;
}
}
There are optimizations you can do , hopefully this gives you an idea
You can use as follows, you need to populate foodList (with values as [Steak,Pizza]) and then set to the bean using following method.
PropertyUtils.setProperty(studentBean, "foods", foodList);
or
BeanUtils.setProperty(studentBean, "foods", foodList);

Json parsing with nested array using Gson

I have not seen an (answered) example on the web which discusses this kind of nested-json-array.
JSON to be parsed:
{
"Field": {
"ObjectsList": [
{
"type": "Num",
"priority": "Low",
"size": 3.43
},
{
"type": "Str",
"priority": "Med",
"size": 2.61
}
]
}
}
I created a class for each 'level' of nested json block. I want to be able to parse the contents of the "ObjectList" array.
Can anyone help me to parse this JSON using Gson in Java?
Any hints or code-snippets would be greatly appreciated.
My approach is the following:
public static void main (String... args) throws Exception
{
URL jsonUrl = new URL("http://jsonUrl.com") // cannot share the url
try (InputStream input = jsonUrl.openStream();
BufferedReader buffReader = new BufferedReader (new InputStreamReader (input, "UTF-8")))
{
Gson gson = new GsonBuilder().create();
ClassA classA = gson.fromJson(buffReader, ClassA.class);
System.out.println(classA);
}
}
}
class ClassA
{
private String field;
// getter & setter //
}
class ClassB
{
private List<ClassC> objList;
// getter & setter //
}
clas ClassC
{
private String type;
private String priority;
private double size;
// getters & setters //
public String printStr()
{
return String.format(type, priority, size);
}
}
The following snippet and source file would help you:
https://github.com/matpalm/common-crawl-quick-hacks/blob/master/links_in_metadata/src/com/matpalm/MetaDataToTldLinks.java#L17
private static ParseResult NO_LINKS = new ParseResult(new HashSet<String>(), 0);
private JsonParser parser;
public static void main(String[] s) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(s[0]));
MetaDataToTldLinks metaDataToTldLinks = new MetaDataToTldLinks();
while (reader.ready()) {
String[] fields = reader.readLine().split("\t");
ParseResult outboundLinks = metaDataToTldLinks.outboundLinks(fields[1]);
System.out.println(tldOf(fields[0]) + " " + outboundLinks.links);
}
}
public MetaDataToTldLinks() {
this.parser = new JsonParser();
}
public ParseResult outboundLinks(String jsonMetaData) {
JsonObject metaData = parser.parse(jsonMetaData.toString()).getAsJsonObject();
if (!"SUCCESS".equals(metaData.get("disposition").getAsString()))
return NO_LINKS;
JsonElement content = metaData.get("content");
if (content == null)
return NO_LINKS;
JsonArray links = content.getAsJsonObject().getAsJsonArray("links");
if (links == null)
return NO_LINKS;
Set<String> outboundLinks = new HashSet<String>();
int numNull = 0;
for (JsonElement linke : links) {
JsonObject link = linke.getAsJsonObject();
if ("a".equals(link.get("type").getAsString())) { // anchor
String tld = tldOf(link.get("href").getAsString());
if (tld == null)
++numNull;
else
outboundLinks.add(tld);
}
}
return new ParseResult(outboundLinks, numNull);
}
public static String tldOf(String url) {
try {
String tld = new URI(url).getHost();
if (tld==null)
return null;
if (tld.startsWith("www."))
tld = tld.substring(4);
tld = tld.trim();
return tld.length()==0 ? null : tld;
}
catch (URISyntaxException e) {
return null;
}
}
public static class ParseResult {
public final Set<String> links;
public final int numNull;
public ParseResult(Set<String> links, int numNull) {
this.links = links;
this.numNull = numNull;
}
}
How about this snippet?:
if (json.isJsonArray()) {
JsonArray array = json.getAsJsonArray();
List<Object> out = Lists.newArrayListWithCapacity(array.size());
for (JsonElement item : array) {
out.add(toRawTypes(item));
}
}

how to get field name of class in java

Hello all sorry my language is Bad!
This is my code:
MyCustomClass temp = new MyCustomClass();
for (int i = 0; i < jsonarray.length(); i++) {
JSONObject obj = jsonarray.getJSONObject(i);
temp.ID = obj.getInt("ID");
temp.PicName = obj.getString("PicName");
temp.PicURL = obj.getString("PicURL");
Items.add(temp);
}
I would like to take this dynamic
Something like this
MyCustomClass temp = new MyCustomClass();
Field[] myFields= MyCustomClass.class.getFields();
for (int i = 0; i < jsonarray.length(); i++) {
JSONObject obj = jsonarray.getJSONObject(i);
for(int j=0;j<myFields.lenghth();j++)
{
myFields[j]=obj.getString(myFields[j].toString());
Items.add(temp);
}
}
How to do it?
*Name of jason fields = Name of MycustomClass Fields
Jackson and Gson will do all this for you.
static class TestClass {
public int id;
public String name;
}
#Test
public void gson() {
Gson gson = new Gson();
TestClass[] item = gson.fromJson("[{'id': 1, 'name': 'testclass'}]", TestClass[].class);
assertThat(item[0].id, is(1));
assertThat(item[0].name, is("testclass"));
assertThat(item.length, is(1));
}
#Test
public void jackson() throws IOException {
ObjectMapper jacksonObjectMapepr = new ObjectMapper();
TestClass[] item = jacksonObjectMapepr.readValue("[{\"id\": 1, \"name\": \"testclass\"}]", TestClass[].class);
assertThat(item[0].id, is(1));
assertThat(item[0].name, is("testclass"));
assertThat(item.length, is(1));
}
However to answer your question, you can look up what each field with getDeclaredField. But you will have to do quite some work to handle all the type mapping.
#Test
public void sillyWayIDontRecommend() throws NoSuchFieldException, IllegalAccessException {
TestClass[] item = new TestClass[1];
JsonArray array = new JsonParser().parse("[{\"id\": 1, \"name\": \"testclass\"}]").getAsJsonArray();
for(int i = 0; i<array.size(); i++) {
item[i] = new TestClass();
JsonObject object = array.get(i).getAsJsonObject();
for(Map.Entry<String, JsonElement> entry : object.entrySet()) {
Field field = TestClass.class.getDeclaredField(entry.getKey());
if(field.getType().equals(int.class)) {
field.setInt(item[i], entry.getValue().getAsInt());
} else {
field.set(item[i], entry.getValue().getAsString());
}
}
}
assertThat(item[0].id, is(1));
assertThat(item[0].name, is("testclass"));
assertThat(item.length, is(1));
}
With jackson library you are able to set up your Pojos directly with json annotations and you are able to convert your JSON strings directly to java objects.
A generic way for parsing can be something like that:
public static <T> T deserialize(T t, Class<T> clazz, String json) throws JsonParseException, JsonMappingException, IOException{
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(json, clazz);
}
T - is your object and return type
clazz - is your Pojo
json - is your json String
You can call the method like this:
MyCustomClass myCustomClass= new MyCustomClass();
myCustomClass= JsonUtil.deserialize(myCustomClass, MyCustomClass.class, json);
Your Pojo can look like this:
#JsonIgnoreProperties // ignores properties from json String which are not in your Pojo
public class MyCustomClass {
#JsonProperty("anotherNameIfFieldNameIsNotEqual")
private String picName;
private String picURL;
public String getPicName() {
return picName;
}
public void setPicName(String picName) {
this.picName = picName;
}
public String getPicURL() {
return picURL;
}
public void setPicURL(String picURL) {
this.picURL= picURL;
}
}
And this is the maven dependency you need:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.6.3</version>
</dependency>
Documentation and Example
You can get all class field with this construction:
Class class = ...//obtain class object
Field[] methods = class.getFields();
With your class it's:
MyCustomClass temp = new MyCustomClass();
Field[] methods = temp.getFields();

Load _id MongoDB my Object in Java

JAva
I have the following problem.
I have a mobile object.
Calss object mobile
private ObjectId _id;
private String number;
private String nroMatricula;
Get and Set, etc.
When recovery of MongoDB.
String id = "5089e5fde4b07bf6f368366b";
DBObject soid = new BasicDBObject("_id", new ObjectId(id));
String s = MongoAccess.getSingleton().GetOneValueByKey("mobile", soid);
Mobile m = js.fromJson(s, Mobile.class);
public String GetOneValueByKey(String thecollection, DBObject key)
{
String result = null;
try {
DBCollection collection = MDB.getCollection(thecollection);
result = JSON.serialize(collection.findOne(key));
} catch (Exception e) {
Logger.getLogger(MongoAccess.class.getName()).log(Level.SEVERE, e.toString());
}
return result;
}
Recovery data correctly but the _id attribute.
I load the data I have in the database, but it generates a new id.
That should be the correct _id "5089e5fde4b07bf6f368366b" but that is not the charge on the object.
I can help.
Solution
JsonDeserializer<ObjectId> des = new JsonDeserializer<ObjectId>() {
#Override
public ObjectId deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException {
return new ObjectId(je.getAsJsonObject().get("$oid").getAsString());
}
};
Gson gson = new GsonBuilder().registerTypeAdapter(ObjectId.class, des).create();

Categories