Skip to content Skip to sidebar Skip to footer

Using An Annotation To Serialize Null In Moshi With Nested Event

I am attempting to add a custom annotation to serialize specific values in my model to null when calling the toJSON method from Moshi. I have something working based on this respon

Solution 1:

I've had the same issue and the only solution I found was to make a custom adapter instead of using the SerializeNulls annotation. This way, it will only serialize nulls if the object is null, and serialize it normally with the generated adapter otherwise.

classEventJsonAdapter{
    privateval adapter = Moshi.Builder().build().adapter(Event::class.java)

    @ToJsonfuntoJson(writer: JsonWriter, event: Event?) {
        if (event == null) {
            with(writer) {
                serializeNulls = true
                nullValue()
                serializeNulls = false
            }
        } else {
            adapter.toJson(writer, event)
        }
    }
}

For the generated adapter to work don't forget to annotate the Event class with:

@JsonClass(generateAdapter = true)

The custom adapter can then be added to the moshi builder like this:

Moshi.Builder().add(EventJsonAdapter()).build()

In my case I only needed this for one model in specific. Probably not a good solution if you need it for several, in which case the annotation is more practical, but I'll leave it here since it might help someone else.

Solution 2:

The issue is .serializeNulls() returns an adapter that serializes nulls all the way down the tree.

You can simply copy the implementation for .serializeNulls() and add null check in the toJson method and only use it if it's null like this (sorry for my Java):

import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonReader;
import com.squareup.moshi.JsonWriter;

import java.io.IOException;

import javax.annotation.Nullable;

publicclassNullIfNullJsonAdapter<T> extendsJsonAdapter<T> {
    final JsonAdapter<T> delegate;

    publicNullIfNullJsonAdapter(JsonAdapter<T> delegate) {
        this.delegate = delegate;
    }

    @Overridepublic@Nullable
    T fromJson(JsonReader reader)throws IOException {
        return delegate.fromJson(reader);
    }

    @OverridepublicvoidtoJson(JsonWriter writer, @Nullable T value)throws IOException {
        if (value == null) {
            booleanserializeNulls= writer.getSerializeNulls();
            writer.setSerializeNulls(true);
            try {
                delegate.toJson(writer, value);
            } finally {
                writer.setSerializeNulls(serializeNulls);
            }
        } else {
            delegate.toJson(writer, value);
        }
    }

    @Overridepublic String toString() {
        return delegate + ".serializeNulls()";
    }
}

and then you can use it in the @JsonQualifier

importstatic java.lang.annotation.RetentionPolicy.RUNTIME;

import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.JsonQualifier;
import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;

import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.reflect.Type;
import java.util.Set;

import javax.annotation.Nullable;

@Retention(RUNTIME)@JsonQualifierpublic@interface SerializeNulls {
    JsonAdapter.FactoryJSON_ADAPTER_FACTORY=newJsonAdapter.Factory() {
        @Nullable@Overridepublic JsonAdapter<?> create(Type type, Set<? extendsAnnotation> annotations, Moshi moshi) {
            Set<? extendsAnnotation> nextAnnotations =
                    Types.nextAnnotations(annotations, SerializeNulls.class);
            if (nextAnnotations == null) {
                returnnull;
            }
            returnnewNullIfNullJsonAdapter(moshi.nextAdapter(this, type, nextAnnotations));
        }
    };
}

Post a Comment for "Using An Annotation To Serialize Null In Moshi With Nested Event"