I am creating a JSON in Java:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.google.gson.Gson;
String json = null;
Map<String, String> data1 = new HashMap<String, String>();
Map<String, String> data2 = new HashMap<String, String>();
data1.put("name", "f1");
data1.put("key", "aa1");
data1.put("value", "21");
data2.put("name", "f2");
data2.put("key", "aa1");
data2.put("value", "22");
JSONObject json1 = new JSONObject(data1);
JSONObject json2 = new JSONObject(data2);
JSONArray array = new JSONArray();
array.put(json1);
array.put(json2);
JSONObject finalObject = new JSONObject();
try {
finalObject.put("DeltaRealTime", array);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
json = new Gson().toJson(finalObject);
What I get is the following:
{
"map": {
"DeltaRealTime": {
"myArrayList": [{
"map": {
"name": "f1",
"value": "21",
"key": "aa1"
}
}, {
"map": {
"name": "f2",
"value": "22",
"key": "aa1"
}
}]
}
}
}
But I do not want to have all these extra "map" nodes. What I can I do to remove them? Or what I can I do that I do not have them in the first place?
To simply convert JSONObject to String you can use the toString() meethod. I did the same thing as you did without using the Gson Library and I didn't get any map node.
import java.util.HashMap;
import java.util.Map;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class checkTimeStamp {
public static void main(String[] args){
Map<String, String> data1 = new HashMap<String, String>();
Map<String, String> data2 = new HashMap<String, String>();
data1.put("Hello", "abc");
data1.put("Hello1", "abc");
data1.put("Hello2", "abc");
data2.put("Hello", "abc");
data2.put("Hello1", "abc");
data2.put("Hello2", "abc");
JSONObject json1 = new JSONObject(data1);
JSONObject json2 = new JSONObject(data2);
JSONArray array = new JSONArray();
array.put(json1);
array.put(json2);
JSONObject finalObj = new JSONObject();
try{
finalObj.put("RealTimeData", array);
}
catch(JSONException e){
e.printStackTrace();
}
String json = finalObj.toString();
System.out.println(json);
}
}
And the Output was:
{"RealTimeData":[{"Hello1":"abc","Hello2":"abc","Hello":"abc"},{"Hello1":"abc","Hello2":"abc","Hello":"abc"}]}
I would suggest using an Object to JSON string converter lib like Jackson. You can get a json str in three simple steps and dont have to create any JSON objects:
Steps
Create a POJO class
Populate the POJO object
Convert the object to a JSON string using the method as how below:
ObjectMapper mapper = new ObjectMapper();
mapper.writeValueAsString(FooPOJO);
Ref: http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/
My answer may help anyone in the future as none of the answers above worked for me. I just called toMap() on the JSONObject and all occurences of the map key were gone.
you can try as:
String requestBody=data1.toString();
String requestBody=data2.toString();
Related
In my Spring project i created some tests that check the controllers/ http-api. Is there a way to get the json content of response as de-serialized object?
In other project i used rest assured and there methods to acquire results directly as expected objects.
Here is an example:
MvcResult result = rest.perform( get( "/api/byUser" ).param( "userName","test_user" ) )
.andExpect( status().is( HttpStatus.OK.value() ) ).andReturn();
String string = result.getResponse().getContentAsString();
The method returns a specific type as json. how to convert this json back to an object to tests its contents?
I know ways with jackson or with rest-assured but is there a way within spring/test/mockmvc
Like getContentAs(Class)
As far as I know MockHttpServletResponse (Unlike RestTemplate) doesn't have any method which could convert returned JSON to a particular type.
So what you could do is use Jackson ObjectMapper to convert JSON string to a particular type
Something like this
String json = rt.getResponse().getContentAsString();
SomeClass someClass = new ObjectMapper().readValue(json, SomeClass.class);
This will give you more control for you to assert different things.
Having said that, MockMvc::perform returns ResultActions which has a method andExpect which takes ResultMatcher. This has a lot of options to test the resulting json without converting it to an object.
For example
mvc.perform( .....
......
.andExpect(status().isOk())
.andExpect(jsonPath("$.firstname").value("john"))
.andExpect(jsonPath("$.lastname").value("doe"))
.andReturn();
This might be of use:
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.togondo.config.database.MappingConfig;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultHandler;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
#Slf4j
#Getter
public class CustomResponseHandler<T> implements ResultHandler {
private final Class<? extends Collection> collectionClass;
private T responseObject;
private String responseData;
private final Class<T> type;
private Map<String, String> headers;
private String contentType;
public CustomResponseHandler() {
this.type = null;
this.collectionClass = null;
}
public CustomResponseHandler(Class type) {
this.type = type;
this.collectionClass = null;
}
public CustomResponseHandler(Class type, Class<? extends Collection> collectionClass) {
this.type = type;
this.collectionClass = collectionClass;
}
protected <T> T responseToObject(MockHttpServletResponse response, Class<T> type) throws IOException {
String json = getResponseAsContentsAsString(response);
if (org.apache.commons.lang3.StringUtils.isEmpty(json)) {
return null;
}
return MappingConfig.getObjectMapper().readValue(json, type);
}
protected <T> T responseToObjectCollection(MockHttpServletResponse response, Class<? extends Collection> collectionType, Class<T> collectionContents) throws IOException {
String json = getResponseAsContentsAsString(response);
if (org.apache.commons.lang3.StringUtils.isEmpty(json)) {
return null;
}
ObjectMapper mapper = MappingConfig.getObjectMapper();
JavaType type = mapper.getTypeFactory().constructCollectionType(collectionType, collectionContents);
return mapper.readValue(json, type);
}
protected String getResponseAsContentsAsString(MockHttpServletResponse response) throws IOException {
String content = "";
BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(response.getContentAsByteArray())));
String line;
while ((line = br.readLine()) != null)
content += line;
br.close();
return content;
}
#Override
public void handle(MvcResult result) throws Exception {
if( type != null ) {
if (collectionClass != null) {
responseObject = responseToObjectCollection(result.getResponse(), collectionClass, type);
} else {
responseObject = responseToObject(result.getResponse(), type);
}
}
else {
responseData = getResponseAsContentsAsString(result.getResponse());
}
headers = getHeaders(result);
contentType = result.getResponse().getContentType();
if (result.getResolvedException() != null) {
log.error("Exception: {}", result.getResponse().getErrorMessage());
log.error("Error: {}", result.getResolvedException());
}
}
private Map<String, String> getHeaders(MvcResult result) {
Map<String, String> headers = new HashMap<>();
result.getResponse().getHeaderNames().forEach(
header -> headers.put(header, result.getResponse().getHeader(header))
);
return headers;
}
public String getHeader(String headerName) {
return headers.get(headerName);
}
public String getContentType() {
return contentType;
}
}
And then use it in your tests like this:
CustomResponseHandler<MyObject> responseHandler = new CustomResponseHandler(MyObject.class);
mockMvc.perform(MockMvcRequestBuilders.get("/api/yourmom"))
.andDo(responseHandler)
.andExpect(status().isOk());
MyObject myObject = responseHandler.getResponseObject();
Or if you want to fetch collections:
CustomResponseHandler<Set<MyObject>> responseHandler = new CustomResponseHandler(MyObject.class, Set.class);
.
.
.
Set<MyObject> myObjectSet = responseHandler.getResponseObject();
json = [{"a":"555","b":"ee"},{"a":"556","b":"rr"}]
I tried:
ObjectMapper mapper = new ObjectMapper();
TypeReference<Map<String,String>> typeRef = new TypeReference<Map<String,String>>() {};
HashMap<String, String> result = mapper.readValue(json, typeRef);
but it's not working. I suppose that's the reason is that json is a list and not a single object.
In fact, if json was {"a":"555","b":"ee"}, it works.
In order to solve the problem I'll use Jackson SDK.
Please download the latest version from: http://wiki.fasterxml.com/JacksonDownload
JSON TO MAP EXAMPLE:
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JsonMapExample {
public static void main(String[] args) {
try {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"name\":\"mkyong\", \"age\":29}";
Map<String, Object> map = new HashMap<String, Object>();
// convert JSON string to Map
map = mapper.readValue(json, new TypeReference<Map<String, String>>(){});
System.out.println(map);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Map to JSON EXAMPLE:
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class MapJsonExample{
public static void main(String[] args) {
try {
ObjectMapper mapper = new ObjectMapper();
String json = "";
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "mkyong");
map.put("age", 29);
// convert map to JSON string
json = mapper.writeValueAsString(map);
System.out.println(json);
json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
// pretty print
System.out.println(json);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
JSONArray to HashMaps:
HashMap<String, String> pairs = new HashMap<String, String>();
for (int i = 0; i < myArray.length(); i++) {
JSONObject j = myArray.optJSONObject(i);
Iterator it = j.keys();
while (it.hasNext()) {
String n = it.next();
pairs.put(n, j.getString(n));
}
}
I am pulling my hair out over this. After numerous tutorials, I thought I found the perfect one (7th to be exact. But after following the tutorial, I found out that JSONparse is deprecated. Can someone please give me a solution for this. I just want to read an array from the url and populate a listview.
The array is:
{ "lotInfo":[{"lot":"A","spaces":"198","rates":"3.25"},
{"lot":"B","spaces":"165","rates":"7.50"}]}
MainActivity.Java:
package com.example.sahan.wtf;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
public class MainActivity extends ListActivity {
private Context context;
private static String url = "http://192.168.0.199/get_info.php";
private static final String lot = "lot";
private static final String spaces = "spaces";
private static final String rates = "rates";
ArrayList<HashMap<String, String>> jsonlist = new ArrayList<HashMap<String, String>>();
ListView lv ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new ProgressTask(MainActivity.this).execute();
}
private class ProgressTask extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog;
public ProgressTask(ListActivity activity) {
Log.i("1", "Called");
context = activity;
dialog = new ProgressDialog(context);
}
private Context context;
protected void onPreExecute() {
this.dialog.setMessage("Progress start");
this.dialog.show();
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
ListAdapter adapter = new SimpleAdapter(context, jsonlist, R.layout.list_activity, new String[] { lot, spaces, rates }, new int[] { R.id.lot, R.id.spaces, R.id.rates });
setListAdapter(adapter);
lv = getListView();
}
protected Boolean doInBackground(final String... args) {
JSONParse jParser = new JSONParser();
JSONArray json = jParser.getJSONFromUrl(url);
for (int i = 0; i < json.length(); i++) {
try {
JSONObject c = json.getJSONObject(i);
String vlot = c.getString(lot);
String vspaces = c.getString(spaces);
String vrates = c.getString(rates);
HashMap<String, String> map = new HashMap<String, String>();
map.put(lot, vlot);
map.put(spaces, vspaces);
map.put(rates, vrates);
jsonlist.add(map);
} catch (JSONException e)
{
e.printStackTrace();
}
}
return null;
}
}
}
JSONParser.Java:
package com.example.sahan.wtf;
import android.util.Log;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class JSONParser {
static InputStream is = null;
static JSONArray jarray = null;
static String json = "";
public JSONParser() {
}
public JSONArray getJSONFromUrl(String url) {
StringBuilder builder = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
} else {
Log.e("Error....", "Failed to download file");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
jarray = new JSONArray( builder.toString());
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
return array;
}
}
The error I get is:
Error:(74, 13) error: cannot find symbol class JSONParse
It seems that you have a typo, instead of:
JSONParse jParser = new JSONParser();
Should be:
JSONParser jParser = new JSONParser();
I get Json-data like this:
{
"crowds": [
{
"_id": "55ed5f87cdc20e5b2d7ba546",
"name": "The 1 crowd"
},
{
"_id": "55ed6d1a6cc793110057587d",
"name": "testCrowd"
},
{
"_id": "55ed74e2d960a18c3adb3cd7",
"name": "The crowd"
}
]
}
Corresponding to the Crowd class:
public class Crowd {
private String _id;
private String name;
}
And I want to turn the Json-data into a list of Crowd objects using Gson. The method below is derived from the official Gson examples:
private static Type listCrowdType = new TypeToken<List<Crowd>>(){}.getType();
public void handleJsonResponse(String jsonString) {
JsonParser jsonParser = new JsonParser();
JsonArray array = jsonParser.parse(jsonString).getAsJsonArray();
List<Crowd> crowds = gson.fromJson(array.get(0), listCrowdType);
}
In which case Gson tells me This is not a JSON Array.
I can't even count all the different ways I have tried converting the jsonString and passing it into Gson, but it's never happy, giving me different errors like Expected BEGIN_OBJECT but was BEGIN_STRING etc.
How can it be done?
Something else I tried:
public void handleJsonResponse(String jsonString) {
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(jsonString);
JsonObject jsonObject = jsonElement.getAsJsonObject();
List<Crowd> crowds = gson.fromJson(jsonObject.get("crowds"), listCrowdType);
}
Error: Expected BEGIN_OBJECT but was STRING
You can try my following code:
Gson gson = new Gson();
try {
JSONObject jsonObject = new JSONObject(jsonString);
if (!jsonObject.isNull("crowds")) {
JSONArray jsonArray = jsonObject.getJSONArray("crowds");
Crowd[] crowdList = gson.fromJson(jsonArray.toString(), Crowd[].class);
List<Crowd> crowds = new ArrayList<>(Arrays.asList(crowdList));
}
} catch (JSONException e) {
e.printStackTrace();
}
Hope this helps!
Using MOXy I'm trying to marshal a java class like this to JSON:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Request {
String method;
#XmlAnyElement(lax=true)
Object[] arguments;
}
I would expect something like:
{
"method": "test",
"arguments": ["a", "b"]
}
but the JSON output results to:
{
"method": "test",
"value": ["a", "b"]
}
Where is the value coming from?
If I put a #XmlElementWrapper over the arguments field, it gets even worse:
{
"method":"test",
"arguments":"a""value":["b"]
}
My JUnit TestCase looks like this:
import static org.junit.Assert.assertEquals;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import org.junit.Test;
public class JsonRequestTest {
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public static class Request {
String method;
#XmlAnyElement(lax=true)
Object[] arguments;
} // InvocationRequest
#Test
public void testObjectArray() throws JAXBException {
System.setProperty(JAXBContext.class.getName(), "org.eclipse.persistence.jaxb.JAXBContextFactory");
Map<String, Object> props= new HashMap<String, Object>();
props.put("eclipselink.media-type", "application/json");
props.put("eclipselink.json.include-root", false);
JAXBContext ctx = JAXBContext.newInstance(new Class<?>[]{Request.class},props);
Marshaller m = ctx.createMarshaller();
StringWriter writer = new StringWriter();
Request req = new Request();
req.method="test";
req.arguments = new Object[]{"a","b"};
m.marshal(req, writer);
assertEquals("{\"method\":\"test\", \"arguments\":[\"a\",\"b\"]}", writer.toString());
}
} // class JsonRequestTest
Note: I'm the EclipseLink MOXy lead and a member of the JAXB (JSR-222) expert group.
TL:DR
You can set the following property to override the value key.
props.put(MarshallerProperties.JSON_VALUE_WRAPPER, "arguments");
Full Test Case
Below is the full working test case. In addition to setting the property I removed an extra space you had in your control document to get the test to pass.
import static org.junit.Assert.assertEquals;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.junit.Test;
public class JsonRequestTest {
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public static class Request {
String method;
#XmlAnyElement(lax = true)
Object[] arguments;
} // InvocationRequest
#Test
public void testObjectArray() throws JAXBException {
System.setProperty(JAXBContext.class.getName(),
"org.eclipse.persistence.jaxb.JAXBContextFactory");
Map<String, Object> props = new HashMap<String, Object>();
props.put("eclipselink.media-type", "application/json");
props.put("eclipselink.json.include-root", false);
props.put(MarshallerProperties.JSON_VALUE_WRAPPER, "arguments");
JAXBContext ctx = JAXBContext.newInstance(
new Class<?>[] { Request.class }, props);
Marshaller m = ctx.createMarshaller();
StringWriter writer = new StringWriter();
Request req = new Request();
req.method = "test";
req.arguments = new Object[] { "a", "b" };
m.marshal(req, writer);
assertEquals("{\"method\":\"test\",\"arguments\":[\"a\",\"b\"]}",
writer.toString());
}
} // class JsonRequestTest
#XmlElementWrapper Issue
I have opened the following bug for the issue with #XmlElementWrapper:
http://bugs.eclipse.org/421977