我试图使用Gson自定义序列化将以下类序列化为Json。
public class Product{
public String prodId;
public Double prodPrice;
}
public class GsonUtil {
public static String getJSONString(Object input) throws Exception {
if (input == null) {
throw new Exception("JSON Conversion failed. Input string is null");
}
try {
JsonSerializer<Double> dser = getDoubleSerializer();
Gson gson = new GsonBuilder().serializeNulls()
.registerTypeAdapter(Double.class, dser)
.create();
String jsonStr = gson.toJson(input);
if (jsonStr == null) {
throw new Exception("Json String is null");
}
return jsonStr;
} catch (Exception e) {
}
return null;
}
private static JsonSerializer<Double> getDoubleSerializer() {
JsonSerializer<Double> ser = new JsonSerializer<Double>() {
public JsonElement serialize(Double dval, Type arg1,
JsonSerializationContext arg2) {
if(!(dval.equals(-1.0))){
return new JsonPrimitive(dval);
}
else{
Double retVal = null;
return new JsonPrimitive(retVal);
}
}
};
return ser;
}
}
您可以有一个GSON
实例,而不是每次需要这样的反序列化时都创建另一个实例。Gson支持可以绑定到特定对象字段并用@jsonadapter
注释的特殊类型适配器。注意,它不会影响其他相同类型的对象,除非用这个注释对它们进行注释,因此保留了原始的Gson配置。
因此product.java
可以有prodprice
字段的注释:
final class Product {
@SerializedName("prodId")
String id;
@JsonAdapter(SpecialDoubleTypeAdapter.class)
@SerializedName("prodPrice")
Double price;
}
现在只需创建一个符合您需求的特殊类型适配器:
final class SpecialDoubleTypeAdapter
extends TypeAdapter<Double> {
private static final TypeAdapter<Double> specialDoubleTypeAdapter = new SpecialDoubleTypeAdapter();
// Gson can instantiate it itself even with a private constructor
private SpecialDoubleTypeAdapter() {
}
// In case if it's necessary to instantiate it manually
static TypeAdapter<Double> getSpecialDoubleTypeAdapter() {
return specialDoubleTypeAdapter;
}
@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final Double value)
throws IOException {
// write the value as null if no value provided or it's considered "illegal" (however it's a good place to review and the right-hand expression)
if ( value != null || value < 0 ) {
out.value(value);
} else {
out.nullValue();
}
}
@Override
public Double read(final JsonReader in)
throws IOException {
final JsonToken token = in.peek();
switch ( token ) {
case NULL:
// read the null token, this is mandatory
in.nextNull();
return null;
case NUMBER:
// read the number token as double
final double d = in.nextDouble();
// assuming the negative price should be null, not just -1.0
return d >= 0 ? d : null;
// an opinion-based case group: you can use default
// but in my opinion explicit mapping is explicit
case BEGIN_ARRAY:
case END_ARRAY:
case BEGIN_OBJECT:
case END_OBJECT:
case NAME:
case STRING:
case BOOLEAN:
case END_DOCUMENT:
throw new MalformedJsonException("Unexpected token: " + token);
// so this would never happen unless Gson adds a new token some day...
default:
throw new AssertionError("must never happen");
}
}
}
public static void main(final String... args) {
final Gson gson = new Gson();
test(gson, "{\"prodId\":\"good\",\"prodPrice\":100}");
test(gson, "{\"prodId\":\"bad\",\"prodPrice\":-1}");
}
private static void test(final Gson gson, final String json) {
final Product product = gson.fromJson(json, Product.class);
out.print("Product ");
out.print(product.id);
out.print(", price ");
out.println(product.price);
}
产品好,价格100.0
产品坏,价格为空
您的序列化程序存在一些设计问题。最重要的是,如果发生异常,代码会吞下它,很抱歉,当我看到双retVal=null时,我错过了它;返回新的JsonPrimitive(retVal);
。请永远不要这样做--否则您的代码会对严重的问题保持沉默。接下来,您可以重新抛出异常,这就是它得到的结果:
java.lang.NullPointerException
at com.google.gson.JsonPrimitive.isPrimitiveOrString(JsonPrimitive.java:278)
at com.google.gson.JsonPrimitive.setValue(JsonPrimitive.java:101)
at com.google.gson.JsonPrimitive.<init>(JsonPrimitive.java:56)
at q42278197.m2.Q42278197$1.serialize(Q42278197.java:77)
at q42278197.m2.Q42278197$1.serialize(Q42278197.java:71)
at com.google.gson.internal.bind.TreeTypeAdapter.write(TreeTypeAdapter.java:81)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:69)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:125)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:243)
at com.google.gson.Gson.toJson(Gson.java:669)
at com.google.gson.Gson.toJson(Gson.java:648)
at com.google.gson.Gson.toJson(Gson.java:603)
at com.google.gson.Gson.toJson(Gson.java:583)
at q42278197.m2.Q42278197.getJSONString(Q42278197.java:58)
... 7 more
根本原因是:class
classOfErimity=target.getClass();
在GSON中。Gson有一个特殊的JSONnull
元素:jsonnull
单例,只有一个实例instance
。因此JSONSerializer
可能会返回不存在的值:return jsonnull.instance;
下面是一个重新设计的实现:
private static String toJsonBySpecialDoubles(final Object input)
throws NullPointerException {
if ( input == null ) {
throw new NullPointerException("input");
}
return specialDoubleGson.toJson(input);
}
private static final Gson specialDoubleGson = new GsonBuilder()
.serializeNulls()
.registerTypeAdapter(Double.class, getSpecialDoubleSerializer())
.create();
private static JsonSerializer<Double> getSpecialDoubleSerializer() {
return (value, type, context) -> !value.equals(-1.0) ? new JsonPrimitive(value) : JsonNull.INSTANCE;
}
注意,虽然使用了Java8Lambda,但您可以轻松地将其转换为匿名类。还要注意,您可以有一个Gson实例。这可能就是你所需要的,因为Gson本身可以处理null,等等。
我想序列化特定字段或类的空值。 在GSON中,选项适用于整个JSON。 例子: 使用GSON创建JSON: 电流输出: 期望输出: 如何达到预期的输出? 首选解决方案应具有以下特性: 默认情况下不要序列化空值 为具有特定注释的字段序列化空值。
首先,我想说这是一个大学项目。 我有三节课<代码>订单抽象类和从订单继承的和类。 我使用Gson序列化/反序列化子类,但我遇到了一点问题。订单类有一个字段,gson使用该字段来确定订单类型,DineIn或Delivery。 序列化工作得很好。问题是,每当我尝试反序列化时,类型字段值都不会读取,并且总是设置为null,即使它存在于JSON文件中。当有很多字段时,就会发生这种情况,因为当我尝试在较小的
问题内容: 确定,所以我编辑了问题,因为它不够清楚。 编辑2 :更新了JSON文件。 我在Android应用程序中使用GSON,我需要解析来自服务器的JSON文件,这些文件有点太复杂了。我不想让我的对象结构太沉重,所以我想简化内容: 所以我的对象的结构将不是JSON文件的结构。 例如,如果在JSON中,我有以下内容: 我不想保留我当前的对象结构,即一个对象,其中包含一个和一个“总计”。但是我只想将
我有一个JestClient(elasticsearch)响应,我试图将其反序列化为一个对象。该对象包含两个DateTime字段,而在响应中,它们是字符串,因此我得到: 所以,我创建了一个自定义反序列化器来解决这个问题…然而,无论我做什么,我总是得到同样的错误。不知何故它没有注册使用它? 最后,我试图解析JestClient响应的代码: 无论我尝试什么,我总是得到上面的错误,我甚至不确定在这一点上
我收到的是API长json,例如: 我想用Gson反序列化它。一切正常,但字段的“SOME_FIELD”值总是带有烦人的空格。我想修剪()这个字段值(API不能更改)。我知道我可以使用JsonDeserializer,但我必须手动读取所有字段。是否可以在反序列化时只编辑一个感兴趣的字段,但对其余字段使用自动反序列化?
我有一个不能用Gson正确序列化的类(类只是name和HashMap),所以我编写了一个自定义序列化程序来从HashMap中打印名称和键值对。 此外,这是实际打印的内容,序列化整个对象并不像我所期望的那样工作,也不只是直接打印对象。 任何帮助都将不胜感激。