Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using interface in immutable classes causes problem wit GsonTypeAdapter #822

Open
frank-montyne opened this issue Sep 7, 2018 · 2 comments
Labels

Comments

@frank-montyne
Copy link

frank-montyne commented Sep 7, 2018

Hi,

I have a problem with GsonTypeAdapter when using an interface in a immutable class. Let me explain what I mean with an example:

Interface ITypedDate:

public interface ITypedDate {

	public abstract @Nonnull DateType type();
	public abstract @Nonnull DateTime timestamp();
}

Abstract class AbstractTypedDate:

@Gson.TypeAdapters(emptyAsNulls = true)
@Value.Immutable
@ByNubianImmutablesStyle
@Serial.Version(value = 1)
public abstract class AbstractTypedDate extends GsonUtils implements ITypedDate {

    @Override
    public String toString() {
        return toJson();
    }
}

The class TypedDate is generated by the Immutables library.
Now suppose I have another abstract class that makes use of TypedDate but the field variable is defined as ITypedDate

Interface INumberEvent:

public interface INumberEvent  {

	public abstract @Nullable DateTime timestamp();
	public abstract @Nonnull double numberValue();
	public abstract @Nullable List<ITypedDate> dates();
	public abstract @Nullable String sourceId();
	public abstract @Nullable String itemId();
}

Abstract class AbstractNumberEvent:

@Gson.TypeAdapters(emptyAsNulls = true)
@Value.Immutable
@ByNubianImmutablesStyle
@Serial.Version(value = 1)
public abstract class AbstractNumberEvent extends NumberEventTransformer implements INumberEvent {

    // Builder class.
    public abstract static class Builder implements ICoreEventBuilder {}
    @Value.Default
    public @Nullable String id() {
        return UUID.randomUUID().toString();
    }

     @Override
    public String toString() {
        return toJson();
    }
}

When I am using the Gson object with the registered GsonTypeAdapter for NumberEvent and invoke toJson() then the Json representation for the 'dates' field is an empty list even though inspecting the NumberEvent object instance shows that there are typed dates present.
Some debugging inside Immutables led me to the gson.getTypeAdapter(ITypedDate.class) that does not return the generated Immutables type adapter.
When using

public abstract @Nullable List<TypedDate> dates();

instead of

public abstract @Nullable List<ITypedDate> dates();

everything works as expected.

Is there a way to force the type adapter to be recognized for the interface also?

Best regards,
Frank

@elucash
Copy link
Member

elucash commented Sep 7, 2018

Hi, thank you for raising this! In this case Gson have no registered binding to the generated type adapter from ITypedDate. Only AbstractTypedDate and TypedDate have generated adapters bound. So we need to register the adapter to ITypedDate.

Just to give an idea, it might look something like this

public static TypeAdapterFactory bridgeAdapter(final Class<?> to, final Class<?> from) {
  return new TypeAdapterFactory() {
    @SuppressWarnings("unchecked")
    @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
      if (type.getRawType().equals(to)) {
        return (TypeAdapter<T>) gson.getAdapter(from);
      }
      return null;
    }
    @Override public String toString() {
       return "bridgeAdapter(to=" + to + ", from=" + from);
    }
  };
}
gsonBuilder.registerTypeAdapterFactory(bridgeAdapter(ITypedDate.class, TypedDate.class));

@frank-montyne
Copy link
Author

frank-montyne commented Sep 8, 2018 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants