JsonDeserializer
由于要执行处理的业务逻辑,因此我正在实现自定义。但是某些部分可以解析为标准方式。这是否可能-
我自己处理一些元素,并让一些嵌套元素自动处理?
这是JSON:
{
"id": "10",
"games": ["PZ"],
"definition":
{
"count": 10,
"operatorDefinitions": [
{
"operators": "+",
"first": "1-5",
"second": "1-5",
"result": "2-5"
}
]
}
这是definition
项的自定义反序列化器:
public class FormulaDefinitionGsonAdapter implements JsonDeserializer<FormulaDefinition> {
public FormulaDefinition deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
FormulaDefinition definition = new FormulaDefinition();
JsonObject jsonObject = json.getAsJsonObject();
JsonPrimitive p = jsonObject.getAsJsonPrimitive("count");
definition.setCount(p.getAsInt());
JsonArray array = jsonObject.getAsJsonArray("operatorDefinitions");
if (array == null || array.size() == 0) {
throw new JsonParseException("Element 'operatorDefinitions' is missing!");
}
for (JsonElement jsonElement : array) {
jsonObject = (JsonObject) jsonElement;
p = jsonObject.getAsJsonPrimitive("first");
String sValues = p.getAsString();
Values firstArgValues = Values.parse(sValues);
现在,我想让GSON解析operators
枚举。我可以自己完成,这只是几行代码,但是我更愿意库做很多。
…但是我希望图书馆尽其所能。
好吧,只需使用Gson。
有数据传输对象模式,尤其是Gson映射类,可以完美地解决您的问题。默认情况下,如果Gson能够满足内置功能的映射,并且除了特殊情况外,您不必自己完成工作。此类映射类仅旨在存在于JSON内容和您的业务对象类之间,以便对数据进行(反)序列化(简单地说,DTO仅为此目的而存在,并且与Gson相关的注释不得散布到您的业务类中-
只需将DTO转换为业务对象)。
final class Wrapper {
@SerializedName("id")
@Expose
private final String id = null;
@SerializedName("games")
@Expose
private final List<String> games = null;
@SerializedName("definition")
@Expose
private final FormulaDefinition formulaDefinition = null;
private Wrapper() {
}
@Override
public String toString() {
return new StringBuilder("Wrapper{")
.append("id='").append(id)
.append("', games=").append(games)
.append(", formulaDefinition=").append(formulaDefinition)
.append('}')
.toString();
}
}
package q41323887;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
final class FormulaDefinition {
@SerializedName("count")
@Expose
private /*final*/ int count /*= 0*/; // Gson works with final primitives like `int` strangely
@SerializedName("operatorDefinitions")
@Expose
private final List<OperatorDefinition> operatorDefinitions = null;
private FormulaDefinition() {
}
@Override
public String toString() {
return new StringBuilder("FormulaDefinition{")
.append("count=").append(count)
.append(", operatorDefinitions=").append(operatorDefinitions)
.append('}')
.toString();
}
}
final class OperatorDefinition {
@SerializedName("operators")
@Expose
private final Operator operators = null;
@SerializedName("first")
@Expose
private final String first = null;
@SerializedName("second")
@Expose
private final String second = null;
@SerializedName("result")
@Expose
private final String result = null;
private OperatorDefinition() {
}
@Override
public String toString() {
return new StringBuilder("OperatorDefinition{")
.append("operators=").append(operators)
.append(", first='").append(first)
.append("', second='").append(second)
.append("', result='").append(result)
.append("'}")
.toString();
}
}
enum Operator {
PLUS("+"),
MINUS("-"),
ASTERISK("*"),
SLASH("/");
private static final Map<String, Operator> tokenToOperatorIndex = createTokenToOperatorIndexInJava8();
private final String token;
Operator(final String token) {
this.token = token;
}
static Operator resolveOperator(final String token)
throws NoSuchElementException {
final Operator operator = tokenToOperatorIndex.get(token);
if ( operator == null ) {
throw new NoSuchElementException("Cannot resolve operator by " + token);
}
return operator;
}
private static Map<String, Operator> createTokenToOperatorIndex() {
final Map<String, Operator> index = new HashMap<>();
for ( final Operator operator : values() ) {
index.put(operator.token, operator);
}
return unmodifiableMap(index);
}
private static Map<String, Operator> createTokenToOperatorIndexInJava8() {
final Map<String, Operator> index = Stream.of(values())
.collect(toMap(operator -> operator.token, identity()));
return unmodifiableMap(index);
}
}
然后,由于您本operators
打算成为有效的枚举,因此这是您真正需要自定义JSON反序列化器的唯一地方,仅因为Gson默认规则不了解这些规则。
final class OperatorJsonDeserializer
implements JsonDeserializer<Operator> {
private static final JsonDeserializer<Operator> operatorJsonDeserializer = new OperatorJsonDeserializer();
private OperatorJsonDeserializer() {
}
static JsonDeserializer<Operator> getOperatorJsonDeserializer() {
return operatorJsonDeserializer;
}
@Override
public Operator deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
try {
final String token = json.getAsJsonPrimitive().getAsString();
return resolveOperator(token);
} catch ( final NoSuchElementException ex ) {
throw new JsonParseException(ex);
}
}
}
现在,您可以使用Wrapper
该类反序列化JSON:
// Gson instances are thread-safe and can be easily instantiated once
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(Operator.class, getOperatorJsonDeserializer())
.create();
public static void main(final String... args)
throws IOException {
try ( final Reader reader = new InputStreamReader(EntryPoint.class.getResourceAsStream("/test.json")) ) {
final Wrapper wrapper = gson.fromJson(reader, Wrapper.class);
out.println(wrapper);
// ... convert the wrapper DTO above to your target business object
}
}
输出:
包装器{id = ‘10’,游戏= [PZ],FormulaDefinition = FormulaDefinition {count =
10,operatorDefinitions = [OperatorDefinition {operators = PLUS,first
=‘1-5’,second =‘1-5’,result =’ 2-5’}]}}
我在以下代码片段中对Gson的理解是错误的:
@SerializedName("count")
@Expose
private /*final*/ int count /*= 0*/; // Gson works with final primitives like `int` strangely
实际上,Gson 确实
工作正常。我忘记了Java常量内联。使用获得count
通孔反射Field
效果完美。但是,由于内联,返回了contant值。与相似的普通对象javap -p -c
:
final class ext.Test$Immutable {
private final int foo;
private ext.Test$Immutable();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_0
6: putfield #2 // Field foo:I
9: return
private int getFoo();
Code:
0: iconst_0
1: ireturn
public java.lang.String toString();
Code:
0: ldc #4 // String (IMMUTABLE:0)
2: areturn
}
在这种情况下,甚至toString()
返回一个常数。是的,这就是Java和javac
工作方式。为了禁用这种内联并将final
修饰符添加到该字段,就像周围的所有字段一样,应添加一个非编译时值:
@SerializedName("count")
@Expose
private final int count = constOf(0);
哪里constOf(int)
仅仅是:
private static int constOf(final int value) {
return value;
}
现在,所有传入的DTO字段都可以轻松声明final
。
问题内容: 我想通过Google Gson传输列表对象,但是我不知道如何反序列化泛型类型。 看了这个之后我尝试了什么(BalusC的答案): 但是后来我在日食中遇到了一个错误,说“新的List(){}类型必须实现继承的抽象方法…”,如果我使用快速修复方法,则会得到20个以上的方法存根的怪物。 我很确定有一个更简单的解决方案,但是我似乎找不到它! 编辑: 我现在有 但是,我确实在“ fromJson
我正在尝试使用gson从JSON对象反序列化数据。我有麻烦1)设计一个类。2)从内部列表对象获得一个空对象。 以下是JSON对象的示例 下面是我为json对象创建的类的一个示例,该类将与使用java的gson一起使用 下面是使用gson的示例代码 任何帮助都将不胜感激,我对GSON和检索JSON对象非常陌生。非常感谢你
我想使用Gson将JSON反序列化为对象。我已经定义了相应的类,其中一些类的对象包含在其他对象中。在尝试反序列化整个JSON时,我得到了空值,所以我开始将其拆分。 我已经到了所有低级类都支持自己的地步,但是当我试图反序列化成一个包含那个较小对象的实例的对象时,所有的东西都返回为null。 我的部分JSON: UserProfile类: UPfield类: 用户类: Ufield类: 我的主要观点是
问题内容: 我使用了很多不可变的集合,并且很好奇如何使用Gson反序列化它们。由于没有人回答,而且我自己找到了解决方案,因此我正在简化问题并提出自己的答案。 我有两个问题: 如何为所有人编写一个作品? 如何全部注册? 问题答案: 更新:有https://github.com/acebaggins/gson- serializers ,其中涵盖了许多番石榴集合: 如何编写适用于所有Immutable
问题内容: 我正在使用GSON 1.4,并使用两个通用对象序列化对象,如下所示 。当我对它进行反序列化时 可悲的是我得到了 java.lang.IllegalArgumentException:无法将java.util.ArrayList字段…设置为java.util.LinkedList 这是为什么 ?GSON文档指出,如果我使用object.class参数进行序列化,则它支持泛型。任何想法?谢
我有一个Api,Api如下所示: 如果响应是ok,那么结构将以关键字开头,例如: 问题是:我如何为父类创建一个反序列化器,它也会反序列化子类(作为我的第二种方法),或者我如何用Gson创建一个泛型类,这样包装在周围的每个tyoe都可以与它一起使用,比如: public class DataObjectDeserializer implements JsonDeserializer{