14

我正在使用 AutoValue 扩展来生成我的 Parcelable Android 类。该文档特别指出一个@AutoValue 不能扩展另一个: https ://github.com/google/auto/blob/master/value/userguide/howto.md#inherit

另一位开发人员正在帮助我解决这个问题,并建议“如果您有公共字段,您可以将它们放在两个实现都实现的接口中。” 我假设这意味着库更喜欢组合而不是继承。

我承认,我有点迷路了。如果有人可以提供一个简单的具体示例,说明“子类化” AutoValue 类的最简单方法,我们将不胜感激。这是一个简单的类:

@AutoParcelGson
public abstract class User implements Parcelable {

    public abstract String username();
    public static User create(String username) {
        return builder().username(username).build();
    }

    public static Builder builder() {
        return new AutoParcelGson_User.Builder();
    }

    @AutoParcelGson.Builder
    public interface Builder {
        Builder username(String username);
        User build();
    }
}

我想要另一个名为 Customer 的 @AutoValue 类,它有一些额外的字段。此外,@AutoParcelGson 是我正在使用的 @AutoValue 扩展,但它的行为相同。

4

2 回答 2

0

AutoValue的文档说:«故意不支持此功能,因为无法正确执行。请参阅 Effective Java,第 2 版第 8 项:“在覆盖 equals 时遵守一般约定”。» 一本好书,学到了很多。在第 3 版中,它是第 10 项。简而言之:假设您将User类扩展BetterUser. BetterUser betterUser.equals(User user)在某些情况下可能是正确的,但在这些情况下user.equals(betterUser)没有定义。违反了对称性。这只是问题之一;你尝试的越多,情况就越糟糕。顺便说一句,这不是 AutoValue 类特有的,而是继承的一般问题。

唯一一致的解决方案是创建一个BetterUser不扩展User但具有 type 字段的新类User。这样,您可以根据需要定义其行为BetterUser,而不会影响其他类。或者,如果User只有几个字段,只需复制和粘贴代码。

于 2019-07-28T14:07:30.727 回答
-2

这是一个工作代码示例。我的案例中的测试打印出来{"newString":"foobar","myInt":1,"myString":"asdf"}

import com.fasterxml.jackson.annotation.JsonProperty;
public abstract class BaseEvent {
  @JsonProperty("myInt")
  public abstract int myInt();
  @JsonProperty("myString")
  public abstract String myString();
  public static abstract class Builder <B extends Builder<B>> {
    @JsonProperty("myInt")
    public abstract B myInt(int myInt);
    @JsonProperty("myString")
    public abstract B myString(String myString);
  }
}



import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.google.auto.value.AutoValue;
@AutoValue
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonSerialize(as = ConcreteEvent.class)
@JsonDeserialize(builder = ConcreteEvent.Builder.class)
public abstract class ConcreteEvent extends BaseEvent {
  public static Builder builder() {
    return Builder.builder();
  }
  @JsonProperty("newString")
  public abstract String newString();
  @AutoValue.Builder
  @JsonIgnoreProperties(ignoreUnknown = true)
  public static abstract class Builder extends BaseEvent.Builder<Builder> {
    @JsonCreator
    public static Builder builder() {
      return new AutoValue_ConcreteEvent.Builder();
    }
    @JsonProperty("newString")
    public abstract Builder newString(String newString);
    public abstract ConcreteEvent build();
  }
}





import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
public class ConcreteEventTest {
  @Test
  public void concreteEventTest() throws IOException  {
    ConcreteEvent e = ConcreteEvent.builder().myInt(1).myString("asdf").newString("foobar").build();
    ObjectMapper mapper = new ObjectMapper();
    String jsonStr = mapper.writeValueAsString(e);
    ConcreteEvent newEvent = mapper.readValue(jsonStr, ConcreteEvent.class);
    System.out.println(jsonStr);
    Assert.assertEquals(newEvent, e);
  }
}
于 2020-08-17T21:51:09.293 回答