java - 如果 JsonStr 中缺少任何键/值,如何在从 JsonStr 转换为 PojoClassObj 时抛出异常?

标签 java json gson pojo

我尝试使用@NotNull注释,但它不起作用。如果 JsonString 中缺少任何字段,则会给出 null(String)zero(int)。但我想要的是,如果类中定义的 JsonStr 中缺少任何字段,则应抛出异常。

添加:我的PojoClass可能有对象引用或多级对象引用。我正在使用GsonString转换为obj。 为了获得更多说明,我在下面添加了代码:

JsonStr:

{
   "name":"John",
   "id":1,
   "roll":100,
   "c":{
      "city":"Dhaka",
      "school":"B. govt. School"
   }
}

代码:

public class C {

    private String city;
    private String school;

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }

}

B类:

public class B {

    private String name;
    private int id;
    @NotNull
    private int roll;
    private C c;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getRoll() {
        return roll;
    }

    public void setRoll(int roll) {
        this.roll = roll;
    }

    public C getC() {
        return c;
    }

    public void setC(C c) {
        this.c = c;
    }

}

主类:

try {
                B obj = new B();
                String str = "{\"name\":\"John\",\"id\":1,\"c\":{\"city\":\"dhaka\",\"school\":\"school\"}}";
                obj = gson.fromJson(str, B.class);

            } catch (RuntimeException e) {
                 System.out.println("exception Message");

            }

对于字段滚动,如果 JsonStr 中不存在该字段,我使用 @NotNull 抛出异常,但它给出 0 值而不抛出任何异常。

我该如何实现?

请不要说这是重复的,因为我已经看到了这些问题:

最佳答案

@NotNull 不是 Gson 的一部分,默认情况下它无法处理它(除非您自己添加支持)。此外,可空性检查注释不应该应用于基元字段——一般来说,它没有多大意义。此外,默认的 int 字段值为 0,并且 Gson 不会检查是否从 JSON 文档读取特定字段。但是,如果您满足以下条件,则可以轻松实现它:

  • 通过将基元 int 更改为其可为 null 的包装器 Integer 来稍微更改映射;
  • 实现自定义后处理验证类型适配器。

例如,

final class Person {

    final String name = null;

    final int id = Integer.valueOf(0); // final primitive fields are inlined by javac

    @NotNull
    final Integer roll = null;

    @SerializedName("c")
    final Location location = null;

}
final class Location {

    final String city = null;

    final String school = null;

}

下一步就是创建您自己的类型适配器来检查可为空字段。

final class NotNullTypeAdapterFactory
        implements TypeAdapterFactory {

    // The type adapter factory holds no state, so no need to instantiate it multiple times
    private static final TypeAdapterFactory notNullTypeAdapterFactory = new NotNullTypeAdapterFactory();

    private NotNullTypeAdapterFactory() {
    }

    static TypeAdapterFactory getNotNullTypeAdapterFactory() {
        return notNullTypeAdapterFactory;
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        final Collection<Field> notNullFields = getNotNullFields(typeToken.getRawType());
        // If no @NotNull fields found, then just tell Gson to pick the next best type adapter
        if ( notNullFields.isEmpty() ) {
            return null;
        }
        // If there's at least one @NotNull field, get the original type adapter
        final TypeAdapter<T> delegateTypeAdapter = gson.getDelegateAdapter(this, typeToken);
        return new TypeAdapter<T>() {
            @Override
            public void write(final JsonWriter out, final T value)
                    throws IOException {
                delegateTypeAdapter.write(out, value);
            }

            @Override
            public T read(final JsonReader in)
                    throws IOException {
                try {
                    // Read the value ...
                    final T value = delegateTypeAdapter.read(in);
                    // ... and make some post-processing
                    for ( final Field f : notNullFields ) {
                        if ( f.get(value) == null ) {
                            throw new MalformedJsonException(f + " has no value");
                        }
                    }
                    return value;
                } catch ( final IllegalAccessException ex ) {
                    throw new IOException(ex);
                }
            }
        };
    }

    private static Collection<Field> getNotNullFields(final Class<?> clazz) {
        // Primitive types and java.lang.Object do not have @NotNull
        if ( clazz.isPrimitive() || clazz == Object.class ) {
            return emptyList();
        }
        // Scan the whole hierarchy from the bottom subclass to the top superclass (except java.lang.Object we mentioned above)
        final Collection<Field> notNullFields = new ArrayList<>();
        for ( Class<?> c = clazz; c != Object.class; c = c.getSuperclass() ) {
            for ( final Field f : c.getDeclaredFields() ) {
                if ( f.isAnnotationPresent(NotNull.class) ) {
                    // Don't forget to make private fields accessible
                    f.setAccessible(true);
                    notNullFields.add(f);
                }
            }
        }
        return notNullFields;
    }

}

测试(使用一些 Google Guava 和自定义资源读取器):

private static final Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(getNotNullTypeAdapterFactory())
        .create();

public static void main(final String... args)
        throws IOException {
    for ( final String resourceName : ImmutableList.of("file-with-roll.json", "file-without-roll.json") ) {
        System.out.println("Deserializing " + resourceName);
        try ( final JsonReader jsonReader = getPackageResourceJsonReader(Q44362030.class, resourceName) ) {
            try {
                final Person person = gson.fromJson(jsonReader, Person.class);
                System.out.println(person.name + " " + person.roll);
            } catch ( final Exception ex ) {
                System.out.println("FAILED! " + ex.getMessage());
            }
        }
    }
}

输出:

Deserializing file-with-roll.json
John 100
Deserializing file-without-roll.json
FAILED! com.google.gson.stream.MalformedJsonException: final java.lang.Integer q44362030.Person.roll has no value

类似地,您可以创建另一个 TypeAdapter 来自动检查所有字段,甚至不需要 @NotNull,但这需要更复杂的实现。

关于java - 如果 JsonStr 中缺少任何键/值,如何在从 JsonStr 转换为 PojoClassObj 时抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44362030/

相关文章:

java - hibernate 标准 : Joining table without a mapped association

javascript - 如何使用服务器的 JSON 响应动态填充灰尘模板?

java - 难道这个检查正确响应的Java Json(Gson)代码是不是太多余了?

java - GSON反序列化字符串或字符串数​​组

java - 当没有标记所有内容时,如何使用 Gson 解析 Json 数据

javascript - 如何使 GET 产品与 Strict CSP 兼容?

java - 将 Docker 用于 Spring Boot REST 应用程序

java - JTable 未显示超过 5 列

c++ - 用qml ListView显示Json数据

javascript - 数据包含连续问号时无法理解的 jQuery $.ajax() 行为