So I am parsing a VERY large JSON file with the use of GSON.
The class I'm parsing it into is structure like this:
What I'm trying to do is round the doubles (in the HashSet, in the Geometry class) up to to 4 decimal points. So as doubles are being added to the HashSet, I want to round them up.
public class Contours {
public String name = null;
public String type = null;
ArrayList<Features> features = null;
class Features {
public String type = null;
public Geometry geometry = null;
public Properties properties = null;
}
class Geometry {
public String type = null;
HashSet<double[]> coordinates = null;
}
class Properties {
public String CONTOUR = null;
public int OBJECTID;
public String LAYER = null;
public double ELEVATION;
}
}
Why I can't do this iteratively after GSON has parsed the file?
The file is VERY large, and has 412,064 lines and is 27.5mb large. So doing that will take very long time.
NOTE: this parsing happens every time this app is run, so speed is necessary.
Thanks
You can register a TypeAdapter to modify values as they're read:
public class GsonDoubleAdapterTest {
public static void main(String[] args) {
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Double.class, new DoubleAdapter());
Gson gson = builder.create();
Foo foo = gson.fromJson("{\"baz\": 0.123456}", Foo.class);
System.out.println(foo);
}
}
/**
* A type adapter that rounds doubles during read.
*/
class DoubleAdapter extends TypeAdapter<Double> {
#Override
public void write(JsonWriter out, Double value) throws IOException {
out.value(value);
}
#Override
public Double read(JsonReader in) throws IOException {
return new BigDecimal(in.nextDouble()).setScale(4, RoundingMode.HALF_UP).doubleValue();
}
}
class Foo {
private Double baz;
public Double getBaz() {
return baz;
}
public void setBaz(Double baz) {
this.baz = baz;
}
#Override
public String toString() {
return "Foo[baz=" + baz + ']';
}
}
Related
So i have this JSON file
{
"results":[
"result":{},
"result":{}
]
}
I wish to deserialize it to a java object which contains an array of result objects.
public class Foo(){
#JsonProperty("results")
private Result[] results;
public void setResults(Result[] results){
this.results = results;
}
public Result[] getResults(){
return this.results;
}
}
public class JsonToObject(){
ObjectMapper mp = new ObjectMapper();
public void createObject(String jsonFile){
Foo bar = mp.readValue(jsonFile, Foo.Class)
}
}
My issue is I keep getting deserialization issues as I have not definied "result".
One way I can get around this is to have result as a class variable inside Result but that seems stupid to do and also may cause issues with re-serializing.
How can I convert the JSON so that my class contains an array of result?
Your question program is wrong. There are many problems with your code. Please use below sample:
public class Foo {
#JsonProperty("results")
private Result[] results;
public Foo() {
}
public Result[] getResults() {
return results;
}
public void setResults(Result[] results) {
this.results = results;
}
}
public class Result {
private String name;
public Result() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) throws IOException {
ObjectMapper mp = new ObjectMapper();
String content = "{\"results\":[{\"name\":\"apple\"},{\"name\":\"lemon\"}]}";
Foo bar = mp.readValue(content, Foo.class);
}
I have this Java class:
class Car {
int mileage;
int id;
}
When I tell gson to serialize it, it of course serializes it to:
{
"mileage": 123,
"id": 12345678
}
But what if I want to serialize it to:
{
"mileage": "123",
"id": "12345678"
}
Assuming changing my members from int to String, is not an option, is there a way to tell gson to serialize those int members as strings to the json file?
There are likely many ways to achieve what you desire.
I will share two ways.
FIRST - Using Custom Serialization
SECOND - Using JsonAdapter Annotation - More Simple
Using a custom serialization
public static class CarSerializer implements JsonSerializer<Car> {
public JsonElement serialize(final Car car, final Type type, final JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.add("mileage", new JsonPrimitive(Integer.toString(car.getMileage())));
result.add("id", new JsonPrimitive(Integer.toString(car.getId())));
return result;
}
}
To call this, simply adapt your code or use the following code with a constructor
Car c = new Car(123, 123456789);
com.google.gson.Gson gson = new
GsonBuilder().registerTypeAdapter(Car.class, new CarSerializer())
.create();
System.out.println(gson.toJson(c));
The output should be
{"mileage":"123","id":"12345678"}
Full Code for Example 1:
public class SerializationTest {
public static class Car {
public int mileage;
public int id;
public Car(final int mileage, final int id) {
this.mileage = mileage;
this.id = id;
}
public int getId() {
return id;
}
public void setId(final int id) {
this.id = id;
}
public String getMileage() {
return mileage;
}
public void setMileage(final String mileage) {
this.mileage = mileage;
}
}
public static class CarSerializer implements JsonSerializer<Car> {
public JsonElement serialize(final Car car, final Type type, final JsonSerializationContext context) {
JsonObject result = new JsonObject();
result.add("mileage", new JsonPrimitive(Integer.toString(car.getMileage())));
result.add("id", new JsonPrimitive(Integer.toString(car.getId())));
return result;
}
}
public static void main(final String[] args) {
Car c = new Car(123, 123456789);
com.google.gson.Gson gson = new
GsonBuilder().registerTypeAdapter(Car.class, new CarSerializer())
.create();
System.out.println(gson.toJson(c));
}
}
Using a #JsonAdapter annotation
Use the JsonAdapter Annotation on the Car class
#JsonAdapter(CarAdapter.class)
public class Car {
public int mileage;
public int id;
}
Create the Custom Adapter
public class CarAdapter extends TypeAdapter<Car> {
#Override
public void write(JsonWriter writer, Car car) throws IOException {
writer.beginObject();
writer.name("mileage").value(car.getMileage());
writer.name("id").value(car.getId());
writer.endObject();
}
#Override
public Car read(JsonReader in) throws IOException {
// do something you need
return null;
}
}
To serialize, using this method, use something like this
Car c = new Car(123, 123456789);
Gson gson = new Gson();
String result = gson.toJson(c);
Printing result in this case should output
{"mileage":"123","id":"12345678"}
You may try it this way:
new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.registerTypeAdapter(Integer.class, (JsonSerializer<Integer>)
(integer, type, jsonSerializationContext) -> new
JsonPrimitive(String.valueOf(integer)))
.excludeFieldsWithoutExposeAnnotation().create();
I currently have my POJO class as such for deserializing a json source.
public class OpenBuilding extends Building {
#JsonProperty("BuildingPostCode")
#Override
public String getPostcode() {
return super.getPostcode();
}
}
Where the parent class is as such
public abstract class Buidling {
protected String postcode;
public String getPostcode() {
return this.postcode;
}
}
My issue is that the String postcode isn't getting mapped at all. It works when using the annotation on the field. However since it is an inherited field and I have other children of Building, which use different property names for the same data, I cannot have it implemented in that way.
For example:
public class DirectedBuilding extends Building {
#JsonProperty("Pseudo_PostCode")
#Override
public String getPostcode() {
return super.getPostcode();
}
}
Perhaps try defining a constructor with #JsonCreator.
class Parent {
private final String foo;
public Parent(final String foo) {
this.foo = foo;
}
public String getFoo() {
return foo;
}
}
class Child extends Parent {
#JsonCreator
public Child(#JsonProperty("foo") final String foo) {
super(foo);
}
#JsonProperty("foo")
public String getFoo() {
return super.getFoo();
}
}
public static void main(String[] args) throws Exception {
final ObjectMapper objectMapper = new ObjectMapper();
final Child toSerialize = new Child("fooValue");
// Serialize the object to JSON
final String json = objectMapper.writer()
.withDefaultPrettyPrinter()
.writeValueAsString(toSerialize);
// Prints { "foo" : "fooValue" }
System.out.println(json);
// Deserialize the JSON
final Child deserializedChild = objectMapper.readValue(json, Child.class);
// Prints fooValue
System.out.println(deserializedChild.getFoo());
}
I've a generic field in User.java. I want to use the value of T in json.
public class User<T> {
public enum Gender {MALE, FEMALE};
private T field;
private Gender _gender;
private boolean _isVerified;
private byte[] _userImage;
public T getField() { return field; }
public boolean isVerified() { return _isVerified; }
public Gender getGender() { return _gender; }
public byte[] getUserImage() { return _userImage; }
public void setField(T f) { field = f; }
public void setVerified(boolean b) { _isVerified = b; }
public void setGender(Gender g) { _gender = g; }
public void setUserImage(byte[] b) { _userImage = b; }
}
and mapper class is:
public class App
{
public static void main( String[] args ) throws JsonParseException, JsonMappingException, IOException
{
ObjectMapper mapper = new ObjectMapper();
Name n = new Name();
n.setFirst("Harry");
n.setLast("Potter");
User<Name> user = new User<Name>();
user.setField(n);
user.setGender(Gender.MALE);
user.setVerified(false);
mapper.writeValue(new File("user1.json"), user);
}
}
and the json output is :
{"field":{"first":"Harry","last":"Potter"},"gender":"MALE","verified":false,"userImage":null}
In the output, i want Name to be appeared in place of field. How do i do that. Any help?
I think what u ask is not JSON's default behavior. Field name is the "key" of the json map, not the variable name. U should rename the field or make some String process to do it.
private T field;
change the above to this:
private T name;
You need a custom serializer to do that. That's a runtime data transformation and Jackson has no support for data transformation other than with a custom serializer (well, there's wrapping/unwrapping of value, but let's not go there). Also, you will need to know in advance every type of transformation you want to apply inside your serializer. The following works:
public class UserSerializer extends JsonSerializer<User<?>> {
private static final String USER_IMAGE_FIELD = "userImage";
private static final String VERIFIED_FIELD = "verified";
private static final String FIELD_FIELD = "field";
private static final String NAME_FIELD = "name";
#Override
public void serialize(User<?> value, JsonGenerator jgen, SerializerProvider provider) throws IOException,
JsonProcessingException {
jgen.writeStartObject();
if (value.field instanceof Name) {
jgen.writeFieldName(NAME_FIELD);
} else {
jgen.writeFieldName(FIELD_FIELD);
}
jgen.writeObject(value.field);
jgen.writeStringField("gender", value._gender.name());
jgen.writeBooleanField(VERIFIED_FIELD, value._isVerified);
if (value._userImage == null) {
jgen.writeNullField(USER_IMAGE_FIELD);
} else {
jgen.writeBinaryField(USER_IMAGE_FIELD, value._userImage);
}
jgen.writeEndObject();
}
}
I have this Json code:
{
"term" : {
"PrincipalTranslations" : {
"0" : {
termine:"casa",
traduzione:"home"
}
"1" :{
termine:"testa",
traduzione:"head"
}
"2" :{
termine:"dito",
traduzione:"finger"
}
}
}
}
How can I deserialize the object 0, 1, 2??
If instead of object 0, 1, 2 I wrote object "zero" (and stop), it works!
I've used this implementation:
public class Item {
private term term;
public term getTERM() {
return term;
}
}
public class term {
private PrincipalTranslations PrincipalTranslations;
public PrincipalTranslations getPrincipalTranslations() {
return PrincipalTranslations;
}
}
public class PrincipalTranslations {
private zero zero;
public zero getZero() {
return zero;
}
}
public class zero {
private String termine;
public String gettermine() {
return termine;
}
}
and use it so, it print (in the right way) "casa"
public class MainClass {
public static void main(String[] args) throws IOException {
FileReader reader = new FileReader("/home/peppe/test_ff");
Gson gson = new GsonBuilder().create();
Item p = gson.fromJson(reader, Item.class);
System.out.print(p.getTERM().getPrincipalTranslations().getZero().gettermine());
reader.close();
}
}
If you want to call the object zero, than in your ’Principal Translations‘ class use the ’SerializedName’ annotation: http://google-gson.googlecode.com/svn/tags/1.2.3/docs/javadocs/com/google/gson/annotations/SerializedName.html
It will look like this:
#SerializedName("0")
public Zero zero;