I am strugling with my first Ckan application and from the reading i did i choose to use Gson. From Ckan, for testing, i try to get the user list by http://192.168.1.2:5000/api/action/user_list
This gives me
{"help":"http://192.168.1.2:5000/api/3/action/help_show?name=user_list",
"success":true,
"result":[
{ "openid":null,
"about":null,
"display_name":"default",
"name":"default",
"created":"2015-06-09T22:17:22.228196",
"email_hash":"d41d8cd98f00b204e9800998ecf8427e",
"sysadmin":true,
"activity_streams_email_notifications":false,
"state":"active",
"number_of_edits":0,
"fullname":null,
"id":"d5e49a3d-599d-49f3-9e20-826a03540357",
"number_created_packages":0
}, (..more data here...deleted for convenience)
{ "openid":null,
"about":null,
"display_name":"visitor",
"name":"visitor",
"created":"2015-06-09T22:16:52.785325",
"email_hash":"d41d8cd98f00b204e9800998ecf8427e",
"sysadmin":false,
"activity_streams_email_notifications":false,
"state":"active",
"number_of_edits":0,
"fullname":null,
"id":"9d279d8a-c068-46a5-9516-ed9c8de2f13b",
"number_created_packages":0
}
]
}
My problem is how to read this using Java.
What I did was
class JsonUserReply{
public String help;
public boolean success;
public JsonUsers[] userArray;
JsonUserReply(){}
}
class JsonUsers{
public String openid;
public String about;
public String display_name;
public String name;
public String created;
public String email_hash;
public boolean sysadmin;
public boolean act_email_notif;//"activity_streams_email_notifications"
public String state;
public int edits;
public String fullname;
public String id;
public int numb_cre_packs;//"number_created_packages"
JsonUsers(){}
}
I use the first class because the data provided is "some data, {array of Objects}".
Folowing some tutorials i used this:
Gson gson = new Gson();
Type collectionType = new TypeToken<Collection<JsonUserReply>>(){}.getType();
Collection<JsonUserReply> enums = gson.fromJson(host, collectionType);
This gives me an error on the fromJson command of:
Expected BEGIN_ARRAY but was STRING at line 1 column 1 path $
and the same error i get using this
JsonUserReply myTypes = gson.fromJson(host,JsonUserReply.class);
Edit
JsonUserReply myTypes = gson.fromJson(host,JsonUserReply.class);
throws Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
while digging around i found and used this*
url = new URL(host); //("https://graph.facebook.com/search?q=java&type=post");
InputStream is = url.openStream();
JsonParser parser = Json.createParser(is);
while (parser.hasNext()) {
Event e = parser.next();
if (e == Event.KEY_NAME) {
switch (parser.getString()) {
case "name":
parser.next();
System.out.println("Name "+parser.getString());
break;
case "result":
System.out.println("RESULT1 "+parser.getString());
e=parser.next();
System.out.println("RESULT2 "+e.toString());
break;
default:
System.out.println(parser.getString());
break;
}
}
which even if it is way too complicated to use for my data as they are, it revieled something intresting. inside the case "result": i re-read the parser just to check whats its value. And it turns out that
RESULT1 result
RESULT2 START_ARRAY
RESULT3 START_OBJECT
To me that means that the json object is sending the data with the keyword"START_ARRAY" but Gson is expecting BEGIN_ARRAY. Am i right? apparently these two are not the same. how can i use the Gson way to get the array from my data? Thanks
Related
Is there any simple methods to return exception in JSON using Rest api?
I've already googled this question, but all solutions i see, was about throwing exceptions during some calculations. But what if income parameters are wrong? I mean what if there is sone string instead of int input parameter?
I created some DTO class for input data:
#XmlRootElement
public class RequestDTO implements Serializable{
private static final long serialVersionUID = 1L;
#XmlElement(name = "request_id")
private String requestId;
#XmlElement(name = "site")
private List<String> sitesIds;
#XmlElement(name = "date_begin")
#JsonSerialize(using = DateSerializer.class)
#JsonDeserialize(using = DateDeserializer.class)
private Date dateBegin;
#XmlElement(name = "date_end")
#JsonSerialize(using = JsonDateSerializer.class)
#JsonDeserialize(using = JsonDateDeserializer.class)
private Date dateEnd;
#XmlElement(name = "volume")
private double volume;
// there is getters and setters
}
If i sent something like 'qwerty' instead of 'volume' field in my json request i'l see error message like Runtime. Is it possible to handle it in someway? I mean to return error in json with such structure?
public class ExceptionDTO {
private String shortExceptionMessage;
private String stackTrace;
public ExceptionDTO(String shotExceptionMessage, String stackTrace){
this.shortExceptionMessage = shotExceptionMessage;
this.stackTrace = stackTrace;
}
public String getShortExceptionMessage() {
return shortExceptionMessage;
}
public String getStackTrace() {
return stackTrace;
}
}
UPD1:
#Provider
#Singleton
public class ExceptionMapperProvider implements ExceptionMapper<Exception>{
#Override
public Response toResponse(final Exception e) {
StringBuilder trace = new StringBuilder();
IntStream.range(0, e.getStackTrace().length)
.forEach(i -> trace.append(e.getStackTrace()[i]).append('\n'));
ExceptionDTO exceptionMessage = new ExceptionDTO(
e.toString(),
trace.toString()
);
return Response.status(500).entity(exceptionMessage).build();
}
}
As it's not really clear if you are interested on checking if field or value of the payload is correct, here are a few ways to work with both.
If you want to check if the value for a field is correct (ie volume field value should be greater than zero etc), check out bean validation. This makes use of annotations on the fields you want to verify.
// for example
#Min(value = 0, message = "invalid message")
private double range;
To use your ExceptionDTO as error response whenever one of those validation fails, you can do so by creating an ExceptionMapper<ConstraintViolationException>. check it here for more details.
If you are checking for the invalid field (ie client sends ragne fields instead of range), have a look at the stack trace on what exception is being thrown. Then register an exception mapper with your ExceptionDTO as body.
For example, if UnrecognizedPropertyException is thrown then you can add:
#Provider
public class UnrecognizedPropertyExceptionMapper implements ExceptionMapper<UnrecognizedPropertyException> {
#Override
public Response toResponse(UnrecognizedPropertyException e) {
ExceptionDTO myDTO = // build response
return Response.status(BAD_REQUEST).entity(myDTO).build();
}
}
If you want to validate input parameters in the request, you should return status code 400 (Bad Request) along with the error details. You can simply send json
{ "error": { "message": "string received for parameter x, where as int expected" } with the response status code 400.
`
I did a bit of research and determined that the best way to encode a Java exception in JSON is to use a convention developed by Oasis that looks like this:
{
"error": {
"code": "400",
"message": "main error message here",
"target": "approx what the error came from",
"details": [
{
"code": "23-098a",
"message": "Disk drive has frozen up again. It needs to be replaced",
"target": "not sure what the target is"
}
],
"innererror": {
"trace": [ ... ],
"context": [ ... ]
}
}
}
details is a list that should have an entry for each nested cause exception in the chain.
innererror.trace should include the stack trace if you wish, as a list of string values.
The response status code should be 400 unless you have a good reason for making it something else, and the code in the structure should match whatever you sent.
Write one method to convert a Java exception to this format, and you are done. Use it consistently and your JS code will be able to handle and display the exception values.
More of the details of the other approaches evaluated and dismissed are covered in this blog post on JSON REST API – Exception Handling
https://agiletribe.purplehillsbooks.com/2015/09/16/json-rest-api-exception-handling/
Here is the java method to convert an exception to this format:
public static JSONObject convertToJSON(Exception e, String context) throws Exception {
JSONObject responseBody = new JSONObject();
JSONObject errorTag = new JSONObject();
responseBody.put("error", errorTag);
errorTag.put("code", 400);
errorTag.put("target", context);
JSONArray detailList = new JSONArray();
errorTag.put("details", detailList);
String lastMessage = "";
Throwable runner = e;
while (runner!=null) {
String className = runner.getClass().getName();
String msg = runner.toString();
runner = runner.getCause();
JSONObject detailObj = new JSONObject();
detailObj.put("message",msg);
int dotPos = className.lastIndexOf(".");
if (dotPos>0) {
className = className.substring(dotPos+1);
}
detailObj.put("code",className);
System.out.println(" ERR: "+msg);
detailList.put(detailObj);
}
JSONObject innerError = new JSONObject();
errorTag.put("innerError", innerError);
JSONArray stackList = new JSONArray();
runner = e;
while (runner != null) {
for (StackTraceElement ste : runner.getStackTrace()) {
String line = ste.getFileName() + ":" + ste.getMethodName() + ":" + ste.getLineNumber();
stackList.put(line);
}
stackList.put("----------------");
runner = runner.getCause();
}
errorTag.put("stack", stackList);
return responseBody;
}
I use Gson in my project. But it returns me error
String sig = PortalConfig.getSignature(method, callId, params);
String url = PortalConfig.getUrl(method, callId, sig, params);
String plainResponse = BaseClientCommunicator.executeGetMethod(url);
GsonBuilder builder = new GsonBuilder();
Gson gsonObject = builder.create();
response = gsonObject.fromJson(plainResponse, GetMenuResponse.class);
return response;
example I get a Server-response like this
{
"group":
[
{
"id": "206896",
"name": "Ryż",
"info": "xyz"
},
{
"id": "206897",
"name": "Buraki",
"info": {}
}
]
}
and i have error Expected a string but was BEGIN_OBJECT
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 16151
how should I handle this exception??
public class GetMenuResponse
{
#SerializedName("group")
private group[] group;
//method get and set
//to string method
}
public class group
{
#SerializedName("id")
private String id;
#SerializedName("name")
private String name;
#SerializedName("info")
private String info;
//method get and set
//to string method
}
I do not have access to the database, because I use the API
Problem is at line "info": {} in your json string.
Your class have private String info; String type and in your JSON string it is JSONObject.
It will try to convert JSONObject into String, which give error Expected a string but was BEGIN_OBJECT.GSON API cant able to cast JSONObject into JAVA String.
Value of info in first element of your array group is correct that is "info": "xyz" but same variable value in second element is different.
check value of info if it is String than you need to check your JSON response coming from server, if not than you need to change it's type into class variable.
I'm having trouble trying to make sense of this JSON string.
{
"results":[
{
"user":{
"gender":"female",
"name":{
"title":"miss",
"first":"taylor",
"last":"anderson"
},
"location":{
"street":"3645 dogwood ave",
"city":"roseburg",
"state":"new hampshire",
"zip":"20963"
},
"email":"taylor.anderson49#example.com",
"username":"heavyduck595",
"password":"liverpool",
"salt":"UK`o;9a_",
"md5":"6c8db0305b4591d8d9820d9f8edfd162",
"sha1":"906df4c09f3a87899666cb57bf974bd9b1950ea6",
"sha256":"3b12f5e51688578f845bef8ae1750d3e263c2010691010a80ce632a6b2323c03",
"registered":"1359027425",
"dob":"16243995",
"phone":"(934)-888-7068",
"cell":"(727)-467-8384",
"SSN":"697-20-6143",
"picture":"http://api.randomuser.me/0.3/portraits/women/30.jpg"
},
"seed":"5eaf02877746c7e",
"version":"0.3"
}
]
}
It's the first time I've really used JSON and want to try and interpret it appropriately. This is the code i have thus far:
static class Results{
String results;
}
static class User{
String gender;
String name;
String location;
List<Results> items;
}
private static String readUrl(String urlString) throws Exception {
BufferedReader reader = null;
try {
URL url = new URL(urlString);
reader = new BufferedReader(new InputStreamReader(url.openStream()));
StringBuffer buffer = new StringBuffer();
int read;
char[] chars = new char[1024];
while ((read = reader.read(chars)) != -1)
buffer.append(chars, 0, read);
return buffer.toString();
} finally {
if (reader != null)
reader.close();
}
}
public void larry() throws Exception{
String json = readUrl("http://api.randomuser.me/");
System.out.println(json);
Gson gson = new Gson();
User page = gson.fromJson(json, User.class);
System.out.println(page.name);
for (Results item : page.items)
System.out.println(" " + item.results);
}
There is nothing particularly complicated about JSON, or mapping it to your own Java classes. You just have to understand the basic structure.
Your JSON is an object that has exactly one field; results. This is what {} means:
{ "results": ... }
That field holds an array. That's the [].
{ "results": [ ... ] }
That array holds another object (presumably you'd have more than one in an array, but the JSON you've posted just has one). That object has three fields, one of which ("user") holds another object with the other two being strings.
To map that to your own classes, you simply make them look like that JSON:
class JsonResult {
List<Result> results; // JSON arrays map to Java Lists
}
class Result {
User user;
String seed;
String version;
}
class User {
String gender;
Name name;
// and so on ...
}
class Name {
String title;
String first;
String last;
}
And so forth. You build classes to match the objects (again, denoted by {}) in the JSON, and structure everything accordingly.
As #HotLicks notes in his comment, you can decide not to map to Java classes and use a "clean" parser. In fact, Gson offers this with it's JsonParser class. This will just parse the JSON to a tree from which you can extract the info you want:
JsonElement element = new JsonParser().parse(yourJsonString);
From there you can access the JSON structure using the field names:
JsonObject root = element.getAsJsonObject();
JsonArray array = root.getAsJsonArray("results");
By accessing the JSON structure you can get to whatever you want.
I am using PHP to generate Json that was grabbed from a database query. The result looks like this:
[
{
"title":"Title 1",
"description":"This is description 1",
"add_date":"2013-07-17 10:07:53"
},{
"title":"Title 2",
"description":"This is description 2",
"add_date":"2013-07-17 10:07:53"
}
]
I am using Gson to parse the data, like this:
public class Search{
public Search(String text){
try{
// Snipped (gets the data from the website)
Gson json = new Gson();
Map<String, Event> events = json.fromJson(resultstring, new TypeToken<Map<String, Event>>(){}.getType());
System.out.print(events.get("description"));
}catch(IOException ex){
Logger.getLogger(Search.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
class Event {
private String description;
}
here is the message I am getting while trying to run the code:
Exception in thread "AWT-EventQueue-0" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 3
How would I loop through each one to get the value of description, or title or both?
Several corrections on what you are doing and you should be good to go:
class Event {
private String description;
private String title;
#SerializedName("add_date") private String addDate;
public getDescription() {
return description;
}
}
public Search(String text){
try{
// Snipped (gets the data from the website)
Gson json = new Gson();
Event[] events = json.fromJson(resultstring, Event[].class);
System.out.print(events[0].getDescription());
}catch(IOException ex){
Logger.getLogger(Search.class.getName()).log(Level.SEVERE, null, ex);
}
}
I have corrected your bean class and changed the type of what you convert to (array of Event, because this is what you actually are getting from the PHP service);
I need to take the values from a JSON array and display them. Below is the code I have used.
getresponse class will send a HTTP request to a PHP page and get the relevant JSON array and the public variable res will hold that returned JSON array.
public class JSONConverter {
public void convert(){
getresponse gr=new getresponse();
String json = gr.res;
Data data = new Gson().fromJson(json, Data.class);
System.out.println(data);
}
}
class Data {
private String city;
private int reserve_no;
public String getCity() { return city; }
public int getReserve_no() { return reserve_no; }
public void setTitle(String city) { this.city = city; }
public void setId(int reserve_no) { this.reserve_no = reserve_no; }
public String toString() {
return String.format(city);
}
}
getrespose class
public class getresponse {
public static String res;
public void counter() {
try {
URL url = new URL("http://taxi.net/fetchLatest.php");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String str;
while ((str =br.readLine()) != null) {
res=str;
}
conn.disconnect();
Below is an example of JSON array returned.
[{"reserve_no":"20","city":"city2","street":"street1234","discription":"discription123","date":"2012-10-22
04:47:54","customer":"abc"}]
This code doesn't display the city name of the JSON array returned. can someone help me with this by correcting the code or suggest a better or easier method if any? :)
Nikita already gave you the correct solution, but here it is, step by step.
I reduced your problem to this minimal test:
import com.google.gson.Gson;
public class TestGSON
{
public static void main( String[] args )
{
// that's your JSON sample
String json = "[{\"reserve_no\":\"20\",\"city\":\"city2\",\"street\":\"street1234\",\"discription\":\"discription123\",\"date\":\"2012-10-22 04:47:54\",\"customer\":\"abc\"}]";
// note: we tell Gson to expect an **array** of Data
Data data[] = new Gson().fromJson(json, Data[].class);
System.out.println(data[0]);
}
}
The problem is that your JSON fragment is actually an array of objects, not just an object (hence the [] around it). So, you need to tell GSon it must expect an array of Data, not just a Data object. By the way, the exception that's thrown when executing your code as-is already told you so:
Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2
unless of course it got swallowed by an empty catch block
With respect to the Data class: think twice before you override the toString method like you did here. I would drop that method and just do
System.out.println( data[0].getCity() );
Gson maps json string to your class basing on your class properties names. So Data class has property title which is supposed to be mapped to city in json array. You need to rename you property to city so Gson can figure out where to put city from json array.
Or you can use annotations to explicitly map city to title. Check this: https://sites.google.com/site/gson/gson-user-guide#TOC-JSON-Field-Naming-Support