Spring 具有抽象的数据 Rest 存储库 class / 继承
Spring Data Rest Repository with abstract class / inheritance
我无法通过 class 继承工作获得 Spring 数据。
我想要一个单一的 JSON 端点来处理我所有的具体 classes。
回购:
public interface AbstractFooRepo extends KeyValueRepository<AbstractFoo, String> {}
摘要class:
@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;
}
具体class:
public class MyFoo extends AbstractFoo { }
现在当用 {"type":"MY_FOO"}
调用 POST /abstractFoos
时,它告诉我:java.lang.IllegalArgumentException: PersistentEntity must not be null!
。
这似乎发生了,因为 Spring 不知道 MyFoo
。
有没有什么方法可以告诉 Spring 数据 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);
}
}
请参阅此已解决 jira task for details of what is currently supported in spring-data-rest regarding JsonTypeInfo
. And this 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
类型信息是从常规 属性 中提取的。一个例子有助于理解这种添加类型信息的方式:
摘要class:
@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();
}
和子class:
@Entity @DiscriminatorValue("D")
@Getter @Setter
public class DecimalValue extends Value {
@Column(name = "DECIMAL_VALUE")
private BigDecimal value;
public String getType() {
return "DECIMAL";
}
}
我正在使用 Spring 引导 1.5.1
和 Spring 数据发布 Ingalls
。
KeyValueRepository
不适用于继承。它使用每个已保存对象的 class 名称来查找相应的 key-value-store。例如。 save(new Foo())
会将保存的对象放入 Foo
集合中。 abstractFoosRepo.findAll()
将在 AbstractFoo
集合中查找,但不会找到任何 Foo
对象。
这是使用 MongoRepository 的工作代码:
Application.java
默认 Spring 引导应用程序启动器。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
AbstractFoo.java
我测试了 include = JsonTypeInfo.As.EXISTING_PROPERTY
和 include = JsonTypeInfo.As.PROPERTY
。两者似乎都工作正常!
甚至可以使用自定义 JacksonModule 注册 Jackson 子类型。
重要提示:强烈推荐 @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 & 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
的所有 class 对象,对象将被放置在 _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
不起作用)。如果没有这个注释,我在继承 classes. 中尝试使用 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 { }
}
我无法通过 class 继承工作获得 Spring 数据。
我想要一个单一的 JSON 端点来处理我所有的具体 classes。
回购:
public interface AbstractFooRepo extends KeyValueRepository<AbstractFoo, String> {}
摘要class:
@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;
}
具体class:
public class MyFoo extends AbstractFoo { }
现在当用 {"type":"MY_FOO"}
调用 POST /abstractFoos
时,它告诉我:java.lang.IllegalArgumentException: PersistentEntity must not be null!
。
这似乎发生了,因为 Spring 不知道 MyFoo
。
有没有什么方法可以告诉 Spring 数据 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);
}
}
请参阅此已解决 jira task for details of what is currently supported in spring-data-rest regarding JsonTypeInfo
. And this 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
类型信息是从常规 属性 中提取的。一个例子有助于理解这种添加类型信息的方式:
摘要class:
@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();
}
和子class:
@Entity @DiscriminatorValue("D")
@Getter @Setter
public class DecimalValue extends Value {
@Column(name = "DECIMAL_VALUE")
private BigDecimal value;
public String getType() {
return "DECIMAL";
}
}
我正在使用 Spring 引导 1.5.1
和 Spring 数据发布 Ingalls
。
KeyValueRepository
不适用于继承。它使用每个已保存对象的 class 名称来查找相应的 key-value-store。例如。 save(new Foo())
会将保存的对象放入 Foo
集合中。 abstractFoosRepo.findAll()
将在 AbstractFoo
集合中查找,但不会找到任何 Foo
对象。
这是使用 MongoRepository 的工作代码:
Application.java
默认 Spring 引导应用程序启动器。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
AbstractFoo.java
我测试了
include = JsonTypeInfo.As.EXISTING_PROPERTY
和include = JsonTypeInfo.As.PROPERTY
。两者似乎都工作正常!甚至可以使用自定义 JacksonModule 注册 Jackson 子类型。
重要提示:强烈推荐
@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 & 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
的所有 class 对象,对象将被放置在_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
不起作用)。如果没有这个注释,我在继承 classes. 中尝试使用 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 { }
}