具有抽象类/继承的

时间:2017-02-08 19:01:50

标签: spring inheritance spring-data spring-data-rest spring-data-keyvalue

我无法通过类继承工作来获得Spring Data Rest。

我希望有一个JSON端点来处理我所有的具体类。

回购:

public interface AbstractFooRepo extends KeyValueRepository<AbstractFoo, String> {}

抽象类:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
  @JsonSubTypes.Type(value = MyFoo.class, name = "MY_FOO")
})
public abstract class AbstractFoo {
  @Id public String id;
  public String type;
}

具体类:

public class MyFoo extends AbstractFoo { }

现在使用POST /abstractFoos致电{"type":"MY_FOO"}时,它会告诉我:java.lang.IllegalArgumentException: PersistentEntity must not be null!

这似乎发生了,因为Spring不知道MyFoo

有没有办法告诉Spring Data REST MyFoo没有为它创建存储库和REST端点?

(我正在使用Spring Boot 1.5.1和Spring Data REST 2.6.0)

编辑:

Application.java:

@SpringBootApplication
@EnableMapRepositories
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }
}

2 个答案:

答案 0 :(得分:6)

我正在使用Spring Boot 1.5.1和Spring Data Release Ingalls

KeyValueRepository不能继承。它使用每个保存对象的类名来查找相应的键值存储。例如。 save(new Foo())会将保存的对象放在Foo集合中。 abstractFoosRepo.findAll()会在AbstractFoo集合中查看,但无法找到任何Foo对象。

以下是使用MongoRepository的工作代码:

Application.java

默认的Spring Boot Application Starter。

@SpringBootApplication
public class Application {
  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}

AbstractFoo.java

  • 我测试了include = JsonTypeInfo.As.EXISTING_PROPERTYinclude = JsonTypeInfo.As.PROPERTY。两者似乎都运行良好!

  • 甚至可以使用自定义JacksonModule注册Jackson SubTypes。

  • 重要提示: @RestResource(path="abstractFoos")强烈推荐。否则,_links.self链接将指向/foos/bars,而不是/abstractFoos

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
@JsonSubTypes({
  @JsonSubTypes.Type(value = Foo.class, name = "MY_FOO"),
  @JsonSubTypes.Type(value = Bar.class, name = "MY_Bar")
})
@Document(collection="foo_collection")
@RestResource(path="abstractFoos")
public abstract class AbstractFoo {
  @Id public String id;
  public abstract String getType();
}

AbstractFooRepo.java

这里没什么特别的

public interface AbstractFooRepo extends MongoRepository<AbstractFoo, String> { }

Foo.java&amp; Bar.java

@Persistent
public class Foo extends AbstractFoo {
  @Override
  public String getType() {
    return "MY_FOO";
  }
}

@Persistent
public class Bar extends AbstractFoo {
  @Override
  public String getType() {
    return "MY_BAR";
  }
}

FooRelProvider.java

  • 如果没有此部分,对象的输出将在_embedded.foos_embedded.bars下的两个数组中分开。
  • supports方法确保对于扩展AbstractFoo的所有类,对象将放置在_embedded.abstractFoos内。
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class FooRelProvider extends EvoInflectorRelProvider {
  @Override
  public String getCollectionResourceRelFor(final Class<?> type) {
    return super.getCollectionResourceRelFor(AbstractFoo.class);
  }

  @Override
  public String getItemResourceRelFor(final Class<?> type) {
    return super.getItemResourceRelFor(AbstractFoo.class);
  }

  @Override
  public boolean supports(final Class<?> delimiter) {
    return AbstractFoo.class.isAssignableFrom(delimiter);
  }
}

修改

  • @Persistent添加到Foo.javaBar.java。 (将其添加到AbstractFoo.java并不起作用)。如果没有这个注释,我在尝试在继承的类中使用JSR 303验证注释时会得到NullPointerExceptions。

重现错误的示例代码:

public class A {
  @Id public String id;
  @Valid public B b;

  // @JsonTypeInfo + @JsonSubTypes
  public static abstract class B {
    @NotNull public String s;
  }

  // @Persistent <- Needed!
  public static class B1 extends B { }
}

答案 1 :(得分:3)

请参阅此解决方案jira task 中的讨论,了解有关JsonTypeInfo的spring-data-rest当前支持的内容的详细信息。而这jira task仍然缺少什么。

总结一下 - 只有@JsonTypeInfo include=JsonTypeInfo.As.EXISTING_PROPERTY目前正在进行序列化和反序列化。

此外,您需要spring-data-rest 2.5.3(Hopper SR3)或更高版本来获得这种有限的支持。

请参阅我的示例应用程序 - https://github.com/mduesterhoeft/spring-data-rest-entity-inheritance/tree/fixed-hopper-sr3-snapshot

使用include=JsonTypeInfo.As.EXISTING_PROPERTY,类型信息从常规属性中提取。一个例子有助于明确这种添加类型信息的方式:

抽象类:

@Entity @Inheritance(strategy= SINGLE_TABLE)
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
        include=JsonTypeInfo.As.EXISTING_PROPERTY,
        property="type")
@JsonSubTypes({
        @Type(name="DECIMAL", value=DecimalValue.class),
        @Type(name="STRING", value=StringValue.class)})
public abstract class Value {

    @Id @GeneratedValue(strategy = IDENTITY)
    @Getter
    private Long id;

    public abstract String getType();
}

子类:

@Entity @DiscriminatorValue("D")
@Getter @Setter
public class DecimalValue extends Value {

    @Column(name = "DECIMAL_VALUE")
    private BigDecimal value;

    public String getType() {
        return "DECIMAL";
    }
}
相关问题