I'm trying to get the JSON values from Distance24 JSON output via Google GSON.
But I can't figure out what and where the Exception comes from (I'm using Google AppEngine with Java).
Here's the class from which i send and get the request and response.
package de.tum.in.eist.distance;
import java.io.IOException;
import javax.inject.Inject;
import java.net.URL;
import com.google.appengine.api.urlfetch.HTTPResponse;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.gson.JsonObject;
import de.tum.in.eist.JsonHelper;
import de.tum.in.eist.URLFetchServiceHelper;
public class Distance24Client {
private final URLFetchService service;
#Inject
public Distance24Client(URLFetchService service) {
this.service = service;
}
public Distance24 getDistanceAPI(String source, String destination) throws IOException {
URL url = new URL("http://www.distance24.org/route.json?stops=" + source + "|" + destination);
HTTPResponse response = service.fetch(url);
String jsonString = URLFetchServiceHelper.toString(response);
try {
JsonObject json = JsonHelper.parse(jsonString);
return toDistance24(json);
} catch (Exception e) {
throw new IOException("Error ocurred in getDistanceAPI(): " + e.getMessage());
}
}
private Distance24 toDistance24(JsonObject response) {
if (!(response.get("stops").getAsJsonObject().getAsJsonArray().size() != 0)) {
throw new IllegalArgumentException("No Status set from Distance24 API");
} else {
JsonObject distances = response.get("distances").getAsJsonObject();
return new Distance24(distances);
}
}
}
And here's the Distance24 Object:
package de.tum.in.eist.distance;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
public class Distance24 {
private int[] distances;
private int totalDistance;
private Double sourceLat;
private Double sourceLon;
private Double destLat;
private Double destLong;
public Distance24(JsonObject distances) {
this.setDistances(getIntArray(distances));
this.setTotalDistance(getSum(this.distances));
this.setSourceLat(distances.get("stops").getAsJsonObject().getAsJsonArray().get(0).getAsJsonObject().get("latitude").getAsDouble());
this.setSourceLon(distances.get("stops").getAsJsonObject().getAsJsonArray().get(0).getAsJsonObject().get("longitude").getAsDouble());
this.setDestLat(distances.get("stops").getAsJsonObject().getAsJsonArray().get(1).getAsJsonObject().get("latitude").getAsDouble());
this.setDestLong(distances.get("stops").getAsJsonObject().getAsJsonArray().get(1).getAsJsonObject().get("longitude").getAsDouble());
}
private int[] getIntArray(JsonObject array) {
JsonArray distances = array.getAsJsonArray();
int[] result = new int[distances.size()];
for(int i = 0; i < distances.size(); i++) {
result[i] = distances.get(i).getAsInt();
}
return result;
}
private int getSum(int[] array) {
int sum = 0;
for(int element : array) {
sum += element;
}
return sum;
}
private void setDistances(int[] distances) {
this.distances = distances;
}
public int getTotalDistance() {
return totalDistance;
}
public void setTotalDistance(int totalDistance) {
this.totalDistance = totalDistance;
}
public Double getSourceLat() {
return sourceLat;
}
public void setSourceLat(Double sourceLat) {
this.sourceLat = sourceLat;
}
public Double getSourceLon() {
return sourceLon;
}
public void setSourceLon(Double sourceLon) {
this.sourceLon = sourceLon;
}
public Double getDestLat() {
return destLat;
}
public void setDestLat(Double destLat) {
this.destLat = destLat;
}
public Double getDestLong() {
return destLong;
}
public void setDestLong(Double destLong) {
this.destLong = destLong;
}
}
As a result, I get the whole JSON Object as a String output for e.getMessage(). So I guess the information retrieving works, even though it's on the wrong part of the code.
Plus in the same try-catch-block of the code (Distance24Client, method "toDistance24") it says, the error ocurred in line 30, which is the return statement of the "toDistance24" method.
(clickable)
Running http://www.distance24.org/route.json?stops=detroit|dublin from my browser gives me
{"stops":[{"region":"Michigan ...
"distances":[5581]}
So distances is an array and not an object.
So your line:
JsonObject distances = response.get("distances").getAsJsonObject();
is wrong. Read distances as a JsonArray.
Create a method to handle array or no-array
public static JsonElement toJsonElement(String jsonString) {
JsonParser parser = new JsonParser();
JsonElement jsonElement = parser.parse(jsonString);
JsonElement result = null;
if (jsonElement instanceof JsonObject) {
result = jsonElement.getAsJsonObject();
} else if (jsonElement instanceof JsonArray) {
result = jsonElement.getAsJsonArray();
} else {
throw new IllegalArgumentException(jsonString + " is not valid JSON stirng");
}
return result;
}
Related
I have a class which represents an ArrayList stored in a file, because I need an ArrayList with multiple gigabytes of data in it which is obviously too large to be stored in memory. The data is represented by a class called Field and the function Field.parse() is just for converting the Field into a String and the other way.
The Field class stores a list of (strange) chess pieces and their coordinates.
My class is working fine, but it takes a long time to add an element to the file and I need my program to run as fast as possible. Does anyone know a more efficient/faster way of doing things?
Also, I am not allowed to use external libraries/apis. Please keep that in mind.
This is the class which is responsible for storing Field objects in a temp file:
private File file;
private BufferedReader reader;
private BufferedWriter writer;
public FieldSaver() {
try {
file = File.createTempFile("chess-moves-", ".temp");
System.out.println(file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
public void add(Field field) {
try {
File temp = File.createTempFile("chess-moves-", ".temp");
writer = new BufferedWriter(new FileWriter(temp));
reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null ) {
writer.write(line);
writer.newLine();
}
reader.close();
writer.write(field.parse());
writer.close();
file.delete();
file = new File(temp.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
}
public Field get(int n) {
try {
reader = new BufferedReader(new FileReader(file));
for (int i = 0; i < n; i++) {
reader.readLine();
}
String line = reader.readLine();
reader.close();
return Field.parse(line);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
And this is the Field class:
private WildBoar wildBoar;
private HuntingDog[] huntingDogs;
private Hunter hunter;
private int size;
#Override
public String toString() {
String result = "Wildschwein: " + wildBoar.toString();
for (HuntingDog dog : huntingDogs) {
result += "; Hund: " + dog.toString();
}
return result + "; Jäger: " + hunter.toString();
}
#Override
public boolean equals(Object obj) {
if (obj instanceof Field) {
Field field = (Field) obj;
HuntingDog[] dogs = field.getHuntingDogs();
return wildBoar.equals(field.getWildBoar()) && hunter.equals(field.getHunter()) && huntingDogs[0].equals(dogs[0]) && huntingDogs[1].equals(dogs[1]) && huntingDogs[2].equals(dogs[2]);
}
return false;
}
public Field(int size, WildBoar wildBoar, HuntingDog[] huntingDogs, Hunter hunter) {
this.size = size;
this.wildBoar = wildBoar;
this.huntingDogs = huntingDogs;
this.hunter = hunter;
}
public WildBoar getWildBoar() {
return wildBoar;
}
public HuntingDog[] getHuntingDogs() {
return huntingDogs;
}
public Hunter getHunter() {
return hunter;
}
public int getSize() {
return size;
}
public static Field parse(String s) {
String[] arr = s.split(",");
WildBoar boar = WildBoar.parse(arr[0]);
Hunter hunter = Hunter.parse(arr[1]);
HuntingDog[] dogs = new HuntingDog[arr.length - 2];
for(int i = 2; i < arr.length; i++) {
dogs[i - 2] = HuntingDog.parse(arr[i]);
}
return new Field(8, boar, dogs, hunter);
}
public String parse() {
String result = wildBoar.parse() + "," + hunter.parse();
for(HuntingDog dog : huntingDogs) {
result += "," + dog.parse();
}
return result;
}
Here's an MCVE to do what you want, based on the information you provided.
You can run it and see that it can save a Field to the file and get a Field by index very quickly.
The Fields are constant length, so you can get a Field by index by going to byte offset of index times field length in bytes. This would be significantly more difficult if the field were not constant length.
import java.io.Closeable;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
public class FieldSaver implements Closeable {
public static void main(String[] args) throws IOException {
File f = File.createTempFile("chess-moves-", ".temp");
try (FieldSaver test = new FieldSaver(f);) {
for (byte i = 0; i < 100; i++) {
test.add(new Field(8, new WildBoar(i, i), new Hunter(i, i), new HuntingDog[] {
new HuntingDog(i, i),
new HuntingDog(i, i),
new HuntingDog(i, i) }));
}
// Get a few Fields by index
System.out.println(test.get(0));
System.out.println(test.get(50));
System.out.println(test.get(99));
// EOF exception, there is no Field 100
// System.out.println(test.get(100));
}
}
private final RandomAccessFile data;
public FieldSaver(File f) throws FileNotFoundException {
data = new RandomAccessFile(f, "rw");
}
public void add(Field field) throws IOException {
data.seek(data.length());
field.write(data);
}
public Field get(int index) throws IOException {
data.seek(index * Field.STORAGE_LENGTH_BYTES);
return Field.read(data);
}
public void close() throws IOException { data.close(); }
static abstract class Piece {
protected byte xPos;
protected byte yPos;
public Piece(DataInput data) throws IOException {
xPos = data.readByte();
yPos = data.readByte();
}
public Piece(byte xPos, byte yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
public void write(DataOutput data) throws IOException {
data.writeByte(xPos);
data.writeByte(yPos);
}
public String toString() { return "[" + xPos + ", " + yPos + "]"; }
}
static class Hunter extends Piece {
public Hunter(byte xPos, byte yPos) { super(xPos, yPos); }
public Hunter(DataInput data) throws IOException { super(data); }
}
static class HuntingDog extends Piece {
public HuntingDog(byte xPos, byte yPos) { super(xPos, yPos); }
public HuntingDog(DataInput data) throws IOException { super(data); }
}
static class WildBoar extends Piece {
public WildBoar(byte xPos, byte yPos) { super(xPos, yPos); }
public WildBoar(DataInput data) throws IOException { super(data); }
}
static class Field {
// size of boar + hunter + 3 dogs
public static final int STORAGE_LENGTH_BYTES = 2 + 2 + (3 * 2);
private int size;
private WildBoar boar;
private Hunter hunter;
private final HuntingDog[] dogs;
public Field(int size, WildBoar wildBoar, Hunter hunter, HuntingDog[] huntingDogs) {
this.size = size;
this.boar = wildBoar;
this.hunter = hunter;
this.dogs = huntingDogs;
}
public String toString() {
String result = "Wildschwein: " + boar.toString();
for (HuntingDog dog : dogs) {
result += "; Hund: " + dog.toString();
}
return result + "; Jäger: " + hunter.toString();
}
public static Field read(DataInput data) throws IOException {
WildBoar boar = new WildBoar(data);
Hunter hunter = new Hunter(data);
HuntingDog[] dogs = new HuntingDog[3];
for (int i = 0; i < 3; i++) {
dogs[i] = new HuntingDog(data);
}
return new Field(8, boar, hunter, dogs);
}
public void write(DataOutput data) throws IOException {
boar.write(data);
hunter.write(data);
for (HuntingDog dog : dogs) {
dog.write(data);
}
}
}
}
Use a Map implementation like Cache from ehcache. This library will optimize for you so you don't have to handle writing and reading to disk and manage when to keep it in memory or on disk. You can just use it as a normal map. You probably want a map instead of a list for faster lookup so the library can optimize even more for you.
http://www.ehcache.org/
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("preConfigured",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class,
ResourcePoolsBuilder.heap(100))
.build())
.build(true);
Cache<Long, String> preConfigured
= cacheManager.getCache("preConfigured", Long.class, String.class);
I am trying to handle if required filed comes with a String value while I expect it as Integer. For example;
{
"transactionTimeMilliseconds": "asd"
}
but it defined as int in Java code.
private int transactionTimeMilliseconds;
#JsonCreator
public Channel(#JsonProperty("transactionTimeMilliseconds") int transactionTimeMilliseconds) {
this.transactionTimeMilliseconds = transactionTimeMilliseconds;
}
I have an exception informer class.
CLASS
#ControllerAdvice
public class ExceptionConfiguration extends ResponseEntityExceptionHandler {
#ExceptionHandler(MismatchedInputException.class) // Or whatever exception type you want to handle
public ResponseEntity<JsonException> handleMissingFieldError(MismatchedInputException exception) { // Or whatever exception type you want to handle
int code = 601;
String message = exception.getMessage().split("\n")[0] + exception.getMessage().split(";")[1].replace("]", "");
JsonException jsonException = new JsonException(code,message);
return ResponseEntity.status(jsonException.getCode()).body(jsonException);
}
#ExceptionHandler(UnrecognizedPropertyException.class) // Or whatever exception type you want to handle
public ResponseEntity<JsonException> handleUnrecognizedFieldError(UnrecognizedPropertyException exception) { // Or whatever exception type you want to handle
int code = 602;
String message = exception.getMessage().split(",")[0] + exception.getMessage().split(";")[1].replace("]", "");
JsonException jsonException = new JsonException(code,message);
return ResponseEntity.status(jsonException.getCode()).body(jsonException);
}
#ExceptionHandler(JsonParseException.class) // Or whatever exception type you want to handle
public ResponseEntity<JsonException> handleJsonParseError(JsonParseException exception) {
int code = 603;
String message = exception.getMessage().split(":")[0] + exception.getMessage().split(";")[1].replace("]", "");
JsonException jsonException = new JsonException(code,message);
return ResponseEntity.status(jsonException.getCode()).body(jsonException);
}
#ExceptionHandler(InvalidFormatException.class) // Or whatever exception type you want to handle
public ResponseEntity<JsonException> handleJsonInvalidFormatError(InvalidFormatException exception) {
int code = 604;
String message = exception.getMessage().split(":")[0] + exception.getMessage().split(";")[1].replace("]", "");
JsonException jsonException = new JsonException(code,message);
return ResponseEntity.status(jsonException.getCode()).body(jsonException);
}
#ExceptionHandler(JsonMappingException.class) // Or whatever exception type you want to handle
public ResponseEntity<JsonException> handleNullFieldError(JsonMappingException exception) {
int code = 605;
String message = exception.getMessage().split(":")[0] + exception.getMessage().split(";")[1].replace("]", "");
JsonException jsonException = new JsonException(code,message);
return ResponseEntity.status(jsonException.getCode()).body(jsonException);
}
}
I have to recognize that value, and if this field is wrong as written in above, set it default value as 0.
Should I write a custom deserializer to solve this problem? Thanks.
something like this worked for me :
class Val {
private int v;
public int getV() {
return v;
}
#JsonSetter // or #JsonProperty("v")
public void setV(String v) {
System.out.println("in setter");
try {
this.v = Integer.parseInt(v);
} catch (Exception e) {
this.v = 0;
}
}
}
Test:
#Test
public void test() throws IOException {
String json = " { \"v\" : 1 } ";
Val v = new ObjectMapper().readValue(json, Val.class);
System.out.println(v.getV()); // prints 1
json = " { \"v\" : \"asd\" } ";
v = new ObjectMapper().readValue(json, Val.class);
System.out.println(v.getV()); // prints 0
}
I tried something like this but couldn't get it to work so far.
class Val {
private int v;
#JsonCreator
public Val(#JsonProperty("v") String v) {
System.out.println("in setter");
try {
this.v = Integer.parseInt(v);
} catch (Exception e) {
this.v = 0;
}
}
public int getV() {
return v;
}
}
{ "StatusCode": 200, "StatusDescription": "OK", "ErrorMessage":
"", "ErrorDetail": "", "Results": [
{
"Key": "AccessTokens",
"Value": "[{\"Key\":\"XXXXX",
\"Value\":\"BABABA\"},{\"Key\":\"DIDADIDA\",\"Value\":\"YYYYY"
} ]"}]}
This is the response i will get when i success call the API. The datatype of "Results" is List. Can anyone explain for me how to get the "Key" and the "Value".
My Object Classes
public class KeyValueItem {
private String Key;
private String Value;
public String getKey() {
return Key;
}
public void setKey(String key) {
Key = key;
}
public String getValue() {
return Value;
}
public void setValue(String value) {
Value = value;
}
}
Response Class
public class RestServiceResponse {
#SerializedName("StatusCode")
#Expose
public int StatusCode;
public int getStatusCode() {
return StatusCode;
}
#SerializedName("StatusDescription")
#Expose
public String StatusDescription;
public String getStatusDescription() {
return StatusDescription;
}
#SerializedName("ErrorMessage")
#Expose
public String ErrorMessage;
public String getErrorMessage() {
return ErrorMessage;
}
#SerializedName("ErrorDetail")
#Expose
public String ErrorDetail;
public String getErrorDetail() {
return ErrorDetail;
}
#SerializedName("Results")
#Expose
public List<KeyValueItem> Results;
public List<KeyValueItem> getResults() {
return Results;
}
}
Anyone help please =(
Some of my code:
public void onResponse(Call<RestServiceResponse> call, Response<RestServiceResponse> response) {
Log.i("ddsddsadsa", String.valueOf(response.code()));
RestServiceResponse restServiceResponse = response.body();
if(restServiceResponse.getStatusCode() == 200){
List<KeyValueItem> list = response.body().getResults();
JSONArray jsonArray = new JSONArray(list);
try {
JSONObject job = jsonArray.getJSONObject(1);
String testttt = job.getString("Key");
Log.i("dsadsadsadas", testttt);
} catch (JSONException e) {
e.printStackTrace();
}
}
2 things you have to understand first.
Your JSON data is not in valid format. It contains \ (slashes) to escape double quotes in key-value pair. To confirm whether the returned JSON data is valid or not please copy & paste your JSON response into JSON validator and Formatter. Maybe problem in server script.
If you're using GsonConvertorFactory with Retrofit, Retrofit will automatically converts JSON response data to POJO internally. So, you don't need parse it again inside onResponse() method. If you get proper JSON response from server side then use it like below.
public void onResponse(Call<RestServiceResponse> call, Response<RestServiceResponse> response) {
// code....
RestServiceResponse restServiceResponse = response.body();
if (restServiceResponse.getStatusCode() == 200) {
List<KeyValueItem> list = response.body().getResults();
for(int i = 0; i < list.size(); i++) {
KeyValueItem kvi = list.get(i);
// do whatever you want with kvi object
}
}
}
public void onResponse(Call<RestServiceResponse> call, Response<RestServiceResponse> response) {
Log.i("ddsddsadsa", String.valueOf(response.code()));
RestServiceResponse restServiceResponse = response.body();
if(restServiceResponse.getStatusCode() == 200){
List<KeyValueItem> list = response.body().getResults();
for(KeyValueItem keyValueItem : list) {
String key = keyValueItem.getKey();
String value = keyValueItem.getValue();
Log.i("Keykeykey", key);
}
try {
JSONArray jsonArray = new JSONArray(value);
for(int i = 0; i < jsonArray.length();i++) {
JSONObject obj = jsonArray.getJSONObject(i);
String keykey = obj.getString("Key");
String VAlll = obj.getString("Value");
Log.i("c1111",keykey);
Log.i("c222222", VAlll);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}else if(restServiceResponse.getErrorMessage() != null){
builder = new AlertDialog.Builder(LoginActivity.this);
builder.setTitle("Error");
builder.setMessage(restServiceResponse.getErrorMessage());
builder.setPositiveButton("Ok",null);
AlertDialog alertDialog = builder.create();
alertDialog.show();
}
}
OK. Btw. i have try this to get my result. and it works!
To answer those about a invalid JSON format maybe because i have changed the value of the JSON so may have some mistake on it.
Below is the final log i get:
74/com.appandus.user.konnect I/Keykeykey: AccessTokens 07-12
17:14:38.177 6274-6274/com.appandus.user.konnect I/c1111: XXXXX 07-12
17:14:38.177 6274-6274/com.appandus.user.konnect I/c222222: BABABA
07-12 17:14:38.177 6274-6274/com.appandus.user.konnect I/c1111: NS/NH
: DIDAIDA 07-12 17:14:38.177 6274-6274/com.appandus.user.konnect
I/c222222: YYYYYY
As it stands I have a data set in the form of a .csv file which you can find here. Also there is some brief documentation on it which you can find here. What I am attempting to do is to manipulate the data set so that I can work with some machine learning algorithms but as it stands I can't seem to print the outputted data to the console
ImageMatrix.java
import java.util.Arrays;
public class ImageMatrix {
public static int[] data;
public int classCode;
public ImageMatrix(int[] data, int classCode) {
assert data.length == 64;
}
public String toString() {
return "Class Code: " + classCode + " DataSet:" + Arrays.toString(data) + "\n";
}
public int[] getData() {
return data;
}
public int getClassCode() {
return classCode;
}
}
ImageMatrixDB.java
import java.io.*;
import java.util.*;
public class ImageMatrixDB implements Iterable<ImageMatrix> {
List<ImageMatrix> list = new ArrayList<ImageMatrix>();
public static ImageMatrixDB load(String f) throws IOException {
ImageMatrixDB result = new ImageMatrixDB();
try (FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr)) {
for (String line; null != (line = br.readLine()); ) {
int lastComma = line.lastIndexOf(',');
int classCode = Integer.parseInt(line.substring(1 + lastComma));
int[] data = Arrays.stream(line.substring(0, lastComma).split(","))
.mapToInt(Integer::parseInt)
.toArray();
result.list.add(new ImageMatrix(data, classCode));
}
System.out.println(ImageMatrix.data.toString());
}
return result;
}
public Iterator<ImageMatrix> iterator() {
return this.list.iterator();
}
public static void main(String[] args){
ImageMatrixDB i = new ImageMatrixDB();
i.load("dataset1.csv"); // <<< ERROR IS HERE
}
}
The error is within my main function on the line i.load(... I know I must be missing something or have made a mistake somewhere, I have tried altering the data from static but it just throws more errors and I can't figure it out. Any ideas?
Your issue is in the ImageMatrix class.
You never set the int[] data in the constructor. You have:
public ImageMatrix(int[] data, int classCode) {
assert data.length == 64;
}
You need:
public ImageMatrix(int[] data, int classCode) {
assert data.length == 64;
this.data = data;
this.classCode = classCode;
}
Here is your updated/complete/working code:
ImageMatrix:
import java.util.*;
public class ImageMatrix {
private int[] data;
private int classCode;
public ImageMatrix(int[] data, int classCode) {
assert data.length == 64;
this.data = data;
this.classCode = classCode;
}
public String toString() {
return "Class Code: " + classCode + " DataSet:" + Arrays.toString(data) + "\n";
}
public int[] getData() {
return data;
}
public int getClassCode() {
return classCode;
}
}
ImageMatrixDB:
import java.util.*;
import java.io.*;
public class ImageMatrixDB implements Iterable<ImageMatrix> {
private List<ImageMatrix> list = new ArrayList<ImageMatrix>();
public ImageMatrixDB load(String f) throws IOException {
try (
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr)) {
String line = null;
while((line = br.readLine()) != null) {
int lastComma = line.lastIndexOf(',');
int classCode = Integer.parseInt(line.substring(1 + lastComma));
int[] data = Arrays.stream(line.substring(0, lastComma).split(","))
.mapToInt(Integer::parseInt)
.toArray();
ImageMatrix matrix = new ImageMatrix(data, classCode);
list.add(matrix);
}
}
return this;
}
public void printResults(){
for(ImageMatrix matrix: list){
System.out.println(matrix);
}
}
public Iterator<ImageMatrix> iterator() {
return this.list.iterator();
}
public static void main(String[] args){
ImageMatrixDB i = new ImageMatrixDB();
try{
i.load("cw2DataSet1.csv");
i.printResults();
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
Your load method can throw an IOException. You need to catch it in order to successfully compile
public static void main(String[] args){
ImageMatrixDB i = new ImageMatrixDB();
try{
i.load("dataset1.csv"); // <<< ERROR IS HERE
}
catch(Exception e){
System.out.println(e.getMessage());
}
}
I came across the issue when I have the following JSONObject (org.json):
{
"float1": 0.0,
"float2": 0.1
}
When I call toString method on the object I get the string:
{"float1": 0,"float2": 0.1}
so 0.0 is converted to 0, which causes many problems for me. Does anybody know how to fix that?
I think this is what you wants. However this solution will force you to use your own class extended from JSONObject and it's only functionality is to override the toString() method of JSONObject, i don't know if it's worth it.
import org.json.JSONObject;
import org.json.JSONException;
public class Test extends JSONObject {
public Test(String in) throws JSONException {
super(in);
}
public static Test jsonObj = null;
public static void main(String[] args) throws JSONException {
jsonObj = new Test("{float1: 0.0, float2: 0.1}");
System.out.println(jsonObj.toString());
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{");
String[] box = JSONObject.getNames(jsonObj);
for (int i = 0; i < JSONObject.getNames(jsonObj).length; i++) {
try {
sb.append(box[i])
.append(" ")
.append(String.format(Locale.ENGLISH, "%.1f",
jsonObj.get(box[i])))
.append(i != JSONObject.getNames(jsonObj).length - 1 ? ","
: "");
} catch (JSONException e) {
e.printStackTrace();
}
}
sb.append("}");
return sb.toString();
}
}
I will try Gson to implement this.
Gson gson = new GsonBuilder().registerTypeAdapter(Double.class, new DoubleSerializer()).create();
TestBean bean = gson.fromJson(jsonInput, TestBean.class);
String jsonOutput = gson.toJson(bean);
DoubleSerializer:
class DoubleSerializer implements JsonSerializer<Double> {
public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(String.format("%.1f", src));
}
}
TestBean.java:
public class TestBean {
private Double float1;
private Double float2;
public Double getFloat1() {
return float1;
}
public void setFloat1(Double float1) {
this.float1 = float1;
}
public Double getFloat2() {
return float2;
}
public void setFloat2(Double float2) {
this.float2 = float2;
}
}
If jsonInput is
{
"float1": 0.0,
"float2": 1.31
}
The jsonOutput will be:
{
"float1": "0.0",
"float2": "1.3"
}