具有抽象类/继承的Spring Data Rest信息库 [英] Spring Data Rest Repository with abstract class / inheritance
问题描述
我无法通过类继承工作获得Spring Data Rest.
I can't get Spring Data Rest with class inheritance working.
我想拥有一个可以处理所有具体类的JSON端点.
I'd like to have a single JSON Endpoint which handles all my concrete classes.
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 { }
现在,当用{"type":"MY_FOO"}
调用POST /abstractFoos
时,它会告诉我:java.lang.IllegalArgumentException: PersistentEntity must not be null!
.
Now when calling POST /abstractFoos
with {"type":"MY_FOO"}
, it tells me: java.lang.IllegalArgumentException: PersistentEntity must not be null!
.
这似乎发生了,因为Spring不了解MyFoo
.
This seems to happen, because Spring doesn't know about MyFoo
.
是否有某种方法可以在不为其创建存储库和REST端点的情况下向Spring Data REST提供有关MyFoo
的信息?
Is there some way to tell Spring Data REST about MyFoo
without creating a Repository and a REST Endpoint for it?
(我正在使用Spring Boot 1.5.1和Spring Data REST 2.6.0)
(I'm using Spring Boot 1.5.1 and Spring Data REST 2.6.0)
Application.java:
Application.java:
@SpringBootApplication
@EnableMapRepositories
public class Application {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
推荐答案
我正在使用Spring Boot 1.5.1
和Spring Data Release Ingalls
.
I'm using Spring Boot 1.5.1
and Spring Data Release Ingalls
.
KeyValueRepository
不适用于继承.它使用每个已保存对象的类名来查找对应的键值存储.例如. save(new Foo())
会将保存的对象放置在Foo
集合内.并且abstractFoosRepo.findAll()
将在AbstractFoo
集合中查找,并且找不到任何Foo
对象.
KeyValueRepository
doesn't work with inheritance. It uses the class name of every saved object to find the corresponding key-value-store. E.g. save(new Foo())
will place the saved object within the Foo
collection. And abstractFoosRepo.findAll()
will look within the AbstractFoo
collection and won't find any Foo
object.
以下是使用MongoRepository的工作代码:
默认的Spring Boot应用程序启动器.
Default 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_PROPERTY
和include = JsonTypeInfo.As.PROPERTY
.两者似乎都可以正常工作!AbstractFoo.java
I've tested
include = JsonTypeInfo.As.EXISTING_PROPERTY
andinclude = JsonTypeInfo.As.PROPERTY
. Both seem to work fine!甚至可以使用自定义的JacksonModule注册Jackson子类型.
It's even possible to register the Jackson SubTypes with a custom JacksonModule.
重要提示:强烈建议
@RestResource(path="abstractFoos")
.否则,_links.self
链接将指向/foos
和/bars
而不是/abstractFoos
.IMPORTANT:
@RestResource(path="abstractFoos")
is highly recommended. Else the_links.self
links will point to/foos
and/bars
instead of/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
这里没什么特别的
AbstractFooRepo.java
Nothing special here
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
的类,将对象放置在_embedded.abstractFoos
中. - Without this part, the output of the objects would be separated in two arrays under
_embedded.foos
and_embedded.bars
. - The
supports
method ensures that for all classes which extendAbstractFoo
, the objects will be placed within_embedded.abstractFoos
.
FooRelProvider.java
@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); } }
编辑
- 在
Foo.java
和Bar.java
中添加了@Persistent
. (将其添加到AbstractFoo.java
不起作用).如果没有此注释,则在尝试在继承的类中使用JSR 303验证注释时,会出现NullPointerExceptions. - Added
@Persistent
toFoo.java
andBar.java
. (Adding it toAbstractFoo.java
doesn't work). Without this annotation I got NullPointerExceptions when trying to use JSR 303 Validation Annotations within inherited classes.
EDIT
重现该错误的示例代码:
Example code to reproduce the error:
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 { } }
这篇关于具有抽象类/继承的Spring Data Rest信息库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- 没有这部分,对象的输出将在