我无法通过类继承工作来获得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);
}
}
答案 0 :(得分:6)
我正在使用Spring Boot 1.5.1
和Spring Data Release Ingalls
。
KeyValueRepository
不能继承。它使用每个保存对象的类名来查找相应的键值存储。例如。 save(new Foo())
会将保存的对象放在Foo
集合中。 abstractFoosRepo.findAll()
会在AbstractFoo
集合中查看,但无法找到任何Foo
对象。
以下是使用MongoRepository的工作代码:
默认的Spring Boot Application Starter。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
我测试了include = JsonTypeInfo.As.EXISTING_PROPERTY
和include = 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();
}
这里没什么特别的
public interface AbstractFooRepo extends MongoRepository<AbstractFoo, String> { }
@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";
}
}
_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.java
和Bar.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";
}
}