3

While converting Java object to Json string using GSON API, I also want to fail this Json conversion if any of the annotated attribute is null.

For example

public class Order{

@SerializedName("orderId")
@Expose
@Required
private Integer id;

//getter & setter available for id
}

Now as I am doing

Order order = new Order();

JSONObject jsonobj = new JSONObject(gson.toJson(order));

I want to fail the above Java to Json transformation if any of the @Required attribute is null Is this possible using GSON?

Preetam Purbia
  • 5,736
  • 3
  • 24
  • 26

1 Answers1

7

I wanted to fail Java to Json conversion, if any of the Java attribute is null which is annotated as @Required, I am able to achieve this using following approach. Please let me know if you see any issues:

class RequiredKeyAdapterFactory implements TypeAdapterFactory {

    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {

        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);

        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out, T value) throws IOException {
                if (value != null) {

                    Field[] fields = value.getClass().getDeclaredFields();

                    for (int i = 0; i < fields.length; i++) {
                        if (fields[i]
                                .isAnnotationPresent(Required.class)) {
                            validateNullValue(value, fields[i]);
                        }

                    }
                }
                delegate.write(out, value);
            }

            private <T> void validateNullValue(T value, Field field) {
                field.setAccessible(true);
                Class t = field.getType();
                Object v = null;
                try {
                    v = field.get(value);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    throw new IllegalArgumentException(e);
                }
                if (t == boolean.class && Boolean.FALSE.equals(v)) {
                    throw new IllegalArgumentException(field + " is null");
                } else if (t.isPrimitive()
                        && ((Number) v).doubleValue() == 0) {

                    throw new IllegalArgumentException(field + " is null");
                } else if (!t.isPrimitive() && v == null) {
                    throw new IllegalArgumentException(field + " is null");

                }
            }

            @Override
            public T read(JsonReader in) throws IOException {
                return delegate.read(in);
            }

        };
    }
}

RequiredKeyAdapterFactory requiredKeyAdapterFactory = new RequiredKeyAdapterFactory();
Gson gson = new GsonBuilder().registerTypeAdapterFactory(requiredKeyAdapterFactory)
        .create();

This is working

Preetam Purbia
  • 5,736
  • 3
  • 24
  • 26
  • hi @Preetam: can you please provide us with definition of Required interface – Anas Salman Sep 19 '16 at 13:33
  • It should be like simple annotation which can be used for all attribute which are mandatory. @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Required { //nothing } – Preetam Purbia Sep 19 '16 at 15:05
  • Note that this will fail if the deserialized JSON contains a primitive number set to 0 (because of the `if (t.isPrimitive() && ((Number) v).doubleValue() == 0)` line) but I don't think there's any good way around that unless you make every serialized value an object. – Anubian Noob Dec 13 '16 at 19:02