在java中是否有一个函数来检查是否有json属性为空?



我有一条JSON格式的消息,我将其转换为JSONObject,并且我有大约30个强制性字段,我必须检查它们是否为空。如果这些强制字段中的一个为空,我将丢弃消息,但是其他字段可以为空而不需要丢弃消息。是否有任何有效的方法,我可以做到这一点,而不通过每个字段和使用isNull()?

此外,JSON对象是嵌套的,所以一个简单的anyNull()函数将不起作用,因为它只会返回,如果对象本身为空,而不是如果变量本身为空。

我尝试使用gson将消息转换为POJO,并为10个对象创建了类

Gson gson = new Gson();
Message message = gson.fromJson(msg, Message.class);

,但由于许多类是嵌套的(其中一个是对象数组),使用简单的空检查器不起作用。

实际上,你的问题不是很清楚,因为你用了一个词" message ";这是指您的特定类,但也可以更通用地指发送/接收消息。

就像内存中的JSON元素:

public static void failOnNullRecursively(final JsonElement jsonElement) {
if ( jsonElement.isJsonNull() ) {
throw new IllegalArgumentException("null!");
}
if ( jsonElement.isJsonPrimitive() ) {
return;
}
if ( jsonElement.isJsonArray() ) {
for ( final JsonElement element : jsonElement.getAsJsonArray() ) {
failOnNullRecursively(element);
}
return;
}
if ( jsonElement.isJsonObject() ) {
for ( final Map.Entry<String, JsonElement> e : jsonElement.getAsJsonObject().entrySet() ) {
failOnNullRecursively(e.getValue());
}
return;
}
throw new AssertionError(jsonElement);
}

或流中的JSON文档:

public final class FailOnNullJsonReader
extends JsonReader {
private FailOnNullJsonReader(final Reader reader) {
super(reader);
}
public static JsonReader create(final Reader reader) {
return new FailOnNullJsonReader(reader);
}
@Override
public void nextNull() {
throw new IllegalStateException(String.format("null at %@!", getPath()));
}
}

它们都将抛出null。但是,您似乎也想验证Message实例:

如果这些必填字段中的一个为空,我将丢弃消息,但是其他字段可以为空而不需要丢弃消息。

所以这说明了为什么上面的空检查不能满足您的需要。你要找的是JSR-303。它不会像您希望的那样高效(消息实例被反序列化,验证也需要时间和资源),但从编码的角度来看,它可能是高效的:

final Set<ConstraintViolation<V>> violations = validator.validate(message);
if ( !violations.isEmpty() ) {
throw new ConstraintViolationException(violations);
}

或甚至将其集成到Gson中,以便它提供中间件:

public final class PostReadTypeAdapterFactory<V>
implements TypeAdapterFactory {
private final Predicate<? super TypeToken<?>> supports;
private final BiConsumer<? super TypeToken<V>, ? super V> onRead;
private PostReadTypeAdapterFactory(final Predicate<? super TypeToken<?>> supports, final BiConsumer<? super TypeToken<V>, ? super V> onRead) {
this.supports = supports;
this.onRead = onRead;
}
public static <V> TypeAdapterFactory create(final Predicate<? super TypeToken<?>> supports, final BiConsumer<? super TypeToken<V>, ? super V> onRead) {
return new PostReadTypeAdapterFactory<>(supports, onRead);
}
@Override
@Nullable
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( !supports.test(typeToken) ) {
return null;
}
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, typeToken);
return new TypeAdapter<T>() {
@Override
public void write(final JsonWriter out, final T value)
throws IOException {
delegate.write(out, value);
}
@Override
public T read(final JsonReader in)
throws IOException {
final T readValue = delegate.read(in);
@SuppressWarnings("unchecked")
final V value = (V) readValue;
@SuppressWarnings("unchecked")
final TypeToken<V> valueTypeToken = (TypeToken<V>) typeToken;
onRead.accept(valueTypeToken, value);
return readValue;
}
};
}
}
public final class Jsr303Support {
private Jsr303Support() {
}
public static <V> TypeAdapterFactory createTypeAdapterFactory(final Validator validator) {
return PostReadTypeAdapterFactory.<V>create(
typeToken -> typeToken.getRawType().isAnnotationPresent(Validate.class),
(typeToken, value) -> {
final Set<ConstraintViolation<V>> violations = validator.validate(value);
if ( !violations.isEmpty() ) {
throw new ConstraintViolationException(violations);
}
}
);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Validate {
}

测试(为简洁起见,使用Lombok):

@Validate
@AllArgsConstructor
@EqualsAndHashCode
@ToString
final class Message {
@NotNull
final String foo;
@NotNull
final String bar;
@NotNull
final String baz;
}
public final class Jsr303SupportTest {
private static final Validator validator;
static {
try ( final ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory() ) {
validator = validatorFactory.getValidator();
}
}
public static final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.disableInnerClassSerialization()
.registerTypeAdapterFactory(Jsr303Support.createTypeAdapterFactory(validator))
.create();
@Test
public void test() {
Assertions.assertEquals(new Message("1", "2", "3"), gson.fromJson("{"foo":"1","bar":"2","baz":"3"}", Message.class));
final ConstraintViolationException ex = Assertions.assertThrows(ConstraintViolationException.class, () -> gson.fromJson("{"foo":"1","bar":null,"baz":"3"}", Message.class));
Assertions.assertEquals(1, ex.getConstraintViolations().size());
}
}

最后,可能是最有效的(在读取JSON流方面),但与JSR-303(和NOT相比非常有限在Gson中工作,因为Gson不会将空检查传播到下游(反)序列化器,这种方式可以用类似的"功能"替换@NotNull。注释:

public final class NotNullTypeAdapterFactory
implements TypeAdapterFactory {
// note no external access
private NotNullTypeAdapterFactory() {
}
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
final TypeAdapter<T> delegate = gson.getAdapter(typeToken);
return new TypeAdapter<T>() {
@Override
public void write(final JsonWriter out, @Nullable final T value)
throws IOException {
if ( value == null ) {
throw new IllegalArgumentException(typeToken + " with null");
}
delegate.write(out, value);
}
@Override
public T read(final JsonReader in)
throws IOException {
@Nullable
final T value = delegate.read(in);
if ( value == null ) {
throw new IllegalArgumentException(typeToken + " with null at " + in.getPath());
}
return value;
}
};
}
}
@AllArgsConstructor
@EqualsAndHashCode
@ToString
final class Message {
@JsonAdapter(NotNullTypeAdapterFactory.class)
final String foo;
@JsonAdapter(NotNullTypeAdapterFactory.class)
final String bar;
@JsonAdapter(NotNullTypeAdapterFactory.class)
final String baz;
}
public final class NotNullTypeAdapterFactoryTest {
public static final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.disableInnerClassSerialization()
.create();
@Test
public void test() {
Assertions.assertEquals(new Message("1", "2", "3"), gson.fromJson("{"foo":"1","bar":"2","baz":"3"}", Message.class));
final IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> gson.fromJson("{"foo":"1","bar":null,"baz":"3"}", Message.class));
Assertions.assertEquals("whatever here, the above does not work anyway", ex.getMessage());
}
}

第三个,JSR-303,看起来最适合你。

最新更新