I'm using Spring Boot 1.5.1
and Spring Data Release Ingalls
.
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.
Here's the working code using MongoRepository:
Application.java
Default Spring Boot Application Starter.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
AbstractFoo.java
I've tested include = JsonTypeInfo.As.EXISTING_PROPERTY
and include = JsonTypeInfo.As.PROPERTY
. Both seem to work fine!
It's even possible to register the Jackson SubTypes with a custom JacksonModule.
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
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
- 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 extend AbstractFoo
, the objects will be placed within _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);
}
}
EDIT
- Added
@Persistent
to Foo.java
and Bar.java
. (Adding it to AbstractFoo.java
doesn't work). Without this annotation I got NullPointerExceptions when trying to use JSR 303 Validation Annotations within inherited classes.
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 { }
}