Gson可选和必填字段 [英] Gson optional and required fields

查看:297
本文介绍了Gson可选和必填字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

应该如何处理 Gson 以及必填字段和可选字段?因为所有字段都是可选的,所以我不能根据响应json是否包含某个键 Gson 将简单地解析为null。



我使用的方法 gson.fromJson(json,mClassOfT);

  {b> 

user_id:128591,user_name:TestUser}

我的课程:

  public class User {

@SerializedName(user_id)
private String mId;

@SerializedName(user_name)
private String mName;

public String getId(){
return mId;
}

public void setId(String id){
mId = id;
}

public String getName(){
return mName;
}

public void setName(String name){
mName = name;


code $
$ b $ p $是$ 如果json不包含 user_id user_name 键?> Gson 会失败>

可能有很多情况下,您可能需要解析至少一些值,而其他值可以是可选的?

是否有任何模式或库可用于全局处理这种情况?



谢谢。

解决方案

正如你注意到的,Gson无法定义一个必需字段,如果缺少某些东西,你只需在反序列化对象中获得 null 在JSON中。

这是一个可重复使用的反序列化器和注解,可以做到这一点。限制是,如果POJO需要一个自定义的反序列化器,你必须进一步,并且在构造器中传入一个 Gson 对象以反序列化为将对象本身或将注释检出移入单独的方法并在解串器中使用它。您也可以通过创建自己的异常并将其传递给 JsonParseException 来改进异常处理,以便通过 getCause()在调用者中。



这就是说,在绝大多数情况下,这将起作用:

  public class App 
{

public static void main(String [] args)
{
Gson gson =
new GsonBuilder()
.registerTypeAdapter(TestAnnotationBean.class,new AnnotatedDeserializer< TestAnnotationBean>())
.create();

String json ={\foo \:\This is foo \,\bar\:\this is bar \} ;
TestAnnotationBean tab = gson.fromJson(json,TestAnnotationBean.class);
System.out.println(tab.foo);
System.out.println(tab.bar);

json ={\foo \:\这是foo \};
tab = gson.fromJson(json,TestAnnotationBean.class);
System.out.println(tab.foo);
System.out.println(tab.bar);

json ={\bar \:\这是bar \};
tab = gson.fromJson(json,TestAnnotationBean.class);
System.out.println(tab.foo);
System.out.println(tab.bar);



@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface JsonRequired
{


class TestAnnotationBean
{
@JsonRequired public String foo;
public String bar;
}

class AnnotatedDeserializer< T>实现JsonDeserializer< T>
{

public T deserialize(JsonElement je,Type type,JsonDeserializationContext jdc)throws JsonParseException
{
T pojo = new Gson()。fromJson(je,type );

Field [] fields = pojo.getClass()。getDeclaredFields();
for(Field f:fields)
{
if(f.getAnnotation(JsonRequired.class)!= null)
{
try
{
f.setAccessible(true);
if(f.get(pojo)== null)
{
throw new JsonParseException(Missing field in JSON:+ f.getName());
}
}
catch(IllegalArgumentException ex)
{
Logger.getLogger(AnnotatedDeserializer.class.getName()).log(Level.SEVERE,null,ex );
}
catch(IllegalAccessException ex)
{
Logger.getLogger(AnnotatedDeserializer.class.getName()).log(Level.SEVERE,null,ex);
}
}
}
返回pojo;


$ b

输出:

 
这是foo
这是bar
这是foo
null
线程maincom中的异常.google.gson.JsonParseException:JSON中缺少字段:foo


How should one deal with Gsonand required versus optional fields?

Since all fields are optional, I can't really fail my network request based on if the response json contains some key, Gsonwill simply parse it to null.

Method I am using gson.fromJson(json, mClassOfT);

For example if I have following json:

{"user_id":128591, "user_name":"TestUser"}

And my class:

public class User {

    @SerializedName("user_id")
    private String mId;

    @SerializedName("user_name")
    private String mName;

    public String getId() {
        return mId;
    }

    public void setId(String id) {
        mId = id;
    }

    public String getName() {
        return mName;
    }

    public void setName(String name) {
        mName = name;
    }
}

Is the any option to get Gson to fail if json would not contain user_id or user_name key?

There can be many cases where you might need at least some values to be parsed and other one could be optional?

Is there any pattern or library to be used to handle this case globally?

Thanks.

解决方案

As you note, Gson has no facility to define a "required field" and you'll just get null in your deserialized object if something is missing in the JSON.

Here's a re-usable deserializer and annotation that will do this. The limitation is that if the POJO required a custom deserializer as-is, you'd have to go a little further and either pass in a Gson object in the constructor to deserialize to object itself or move the annotation checking out into a separate method and use it in your deserializer. You could also improve on the exception handling by creating your own exception and pass it to the JsonParseException so it can be detected via getCause() in the caller.

That all said, in the vast majority of cases, this will work:

public class App
{

    public static void main(String[] args)
    {
        Gson gson =
            new GsonBuilder()
            .registerTypeAdapter(TestAnnotationBean.class, new AnnotatedDeserializer<TestAnnotationBean>())
            .create();

        String json = "{\"foo\":\"This is foo\",\"bar\":\"this is bar\"}";
        TestAnnotationBean tab = gson.fromJson(json, TestAnnotationBean.class);
        System.out.println(tab.foo);
        System.out.println(tab.bar);

        json = "{\"foo\":\"This is foo\"}";
        tab = gson.fromJson(json, TestAnnotationBean.class);
        System.out.println(tab.foo);
        System.out.println(tab.bar);

        json = "{\"bar\":\"This is bar\"}";
        tab = gson.fromJson(json, TestAnnotationBean.class);
        System.out.println(tab.foo);
        System.out.println(tab.bar);
    }
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface JsonRequired
{
}

class TestAnnotationBean
{
    @JsonRequired public String foo;
    public String bar;
}

class AnnotatedDeserializer<T> implements JsonDeserializer<T>
{

    public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException
    {
        T pojo = new Gson().fromJson(je, type);

        Field[] fields = pojo.getClass().getDeclaredFields();
        for (Field f : fields)
        {
            if (f.getAnnotation(JsonRequired.class) != null)
            {
                try
                {
                    f.setAccessible(true);
                    if (f.get(pojo) == null)
                    {
                        throw new JsonParseException("Missing field in JSON: " + f.getName());
                    }
                }
                catch (IllegalArgumentException ex)
                {
                    Logger.getLogger(AnnotatedDeserializer.class.getName()).log(Level.SEVERE, null, ex);
                }
                catch (IllegalAccessException ex)
                {
                    Logger.getLogger(AnnotatedDeserializer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return pojo;

    }
}

Output:

This is foo
this is bar
This is foo
null
Exception in thread "main" com.google.gson.JsonParseException: Missing field in JSON: foo

这篇关于Gson可选和必填字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆