使用GSON时将json NaN序列化为null

ars1skjm  于 2022-11-06  发布在  其他
关注(0)|答案(1)|浏览(335)

是否可以使用GSON将Double NaN序列化为null?
我目前遇到的问题是,当我发布Double NaN时,JavaScript订阅者无法反序列化json消息。

class Value {
    Double value;
}

@Test
public void name() {

    Value newValue = new Value();
    newValue.value = Double.NaN;

    Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create();
    String string = gson.toJson(newValue);

    System.out.println(string);

}

以上代码打印:

{"value":NaN}

我想:

{"value":null}
neekobn8

neekobn81#

只需创建专用的类型适配器工厂,该工厂重写FloatDouble类型适配器,并检查可序列化值是否为NaN或无穷大。

public final class NumberOnlyTypeAdapterFactory
        implements TypeAdapterFactory {

    private static final TypeAdapterFactory instance = new NumberOnlyTypeAdapterFactory();

    private static final TypeToken<Float> floatTypeToken = TypeToken.get(Float.class);
    private static final TypeToken<Double> doubleTypeToken = TypeToken.get(Double.class);

    private NumberOnlyTypeAdapterFactory() {
    }

    public static TypeAdapterFactory getInstance() {
        return instance;
    }

    @Override
    @Nullable
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        final Class<? super T> rawType = typeToken.getRawType();
        final TypeAdapter<? extends Number> typeAdapter;
        if ( rawType == Float.class ) {
            typeAdapter = NumberOnlyTypeAdapter.create(gson.getDelegateAdapter(this, floatTypeToken), v -> Float.isNaN(v), v -> Float.isInfinite(v));
        } else if ( rawType == Double.class ) {
            typeAdapter = NumberOnlyTypeAdapter.create(gson.getDelegateAdapter(this, doubleTypeToken), v -> Double.isNaN(v), v -> Double.isInfinite(v));
        } else {
            return null;
        }
        @SuppressWarnings("unchecked")
        final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) typeAdapter;
        return castTypeAdapter;
    }

    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    private static final class NumberOnlyTypeAdapter<T extends Number>
            extends TypeAdapter<T> {

        private final TypeAdapter<? super T> delegate;
        private final Predicate<? super T> isNan;
        private final Predicate<? super T> isInfinite;

        private static <T extends Number> TypeAdapter<T> create(final TypeAdapter<? super T> delegate, final Predicate<? super T> isNan,
                final Predicate<? super T> isInfinite) {
            return new NumberOnlyTypeAdapter<T>(delegate, isNan, isInfinite)
                    .nullSafe();
        }

        @Override
        public void write(final JsonWriter jsonWriter, final T value)
                throws IOException {
            if ( !isNan.test(value) && !isInfinite.test(value) ) {
                delegate.write(jsonWriter, value);
                return;
            }
            jsonWriter.nullValue();
        }

        @Override
        public T read(final JsonReader jsonReader) {
            throw new UnsupportedOperationException("TODO");
        }

    }

}

下面是一个测试(基元数组用于测试基元浮点数和双精度数,而原始值分别被装箱为FloatDouble):

public final class NumberOnlyTypeAdapterFactoryTest {

    private static final Gson gson = new GsonBuilder()
            .disableInnerClassSerialization()
            .disableHtmlEscaping()
            .registerTypeAdapterFactory(NumberOnlyTypeAdapterFactory.getInstance())
            .create();

    private static Stream<Arguments> test() {
        return Stream.of(
                Arguments.of(Float.class, 0F, Float.NaN, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, (Function<Float, float[]>) v -> new float[]{ v }),
                Arguments.of(Double.class, 0D, Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, (Function<Double, double[]>) v -> new double[]{ v })
        );
    }

    @ParameterizedTest
    @MethodSource
    public <N extends Number, A> void test(
            final Type type,
            final N zeroValue,
            final N nanValue,
            final N negativeInfinityValue,
            final N positiveInfinityValue,
            final Function<? super N, ? extends A> convertToPrimitiveArray
    ) {
        Assertions.assertEquals("0.0", gson.toJson(zeroValue));
        Assertions.assertEquals("null", gson.toJson(nanValue));
        Assertions.assertEquals("null", gson.toJson(negativeInfinityValue));
        Assertions.assertEquals("null", gson.toJson(positiveInfinityValue));
        Assertions.assertEquals("null", gson.toJson(null, type));
        Assertions.assertEquals("[0.0]", gson.toJson(convertToPrimitiveArray.apply(zeroValue)));
        Assertions.assertEquals("[null]", gson.toJson(convertToPrimitiveArray.apply(nanValue)));
        Assertions.assertEquals("[null]", gson.toJson(convertToPrimitiveArray.apply(negativeInfinityValue)));
        Assertions.assertEquals("[null]", gson.toJson(convertToPrimitiveArray.apply(positiveInfinityValue)));
    }

}

相关问题