是否可以通过SubTypes和Spring Data REST定义不同的预测 使用关于类类型的最具体的投影?
此问题已在JIRA问题DATAREST-739上公开,并且还存在合并提交,但这不会出现在官方changelog上,而且我也没有找到任何文档或指南来解决当前版本。
问题中使用的用例示例是:
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="type")
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="type")
public abstract class Message implements Identifiable<UUID> { ... }
@Entity
@DiscriminatorValue("TEXT")
@JsonTypeName("TEXT")
public class TextMessage extends Message { ... }
@Entity
@DiscriminatorValue("TODO")
@JsonTypeName("TODO")
public class TodoMessage extends Message { Boolean isDone; }
@Projection(name = "summary", types = TodoMessage.class)
public class TodoMessageSummary { Boolean getIsDone(); }
@Projection(name = "summary", types = TextMessage.class)
public class TextMessageSummary { ... }
public interface MessageRepo extends JpaRepository<Message, UUID> { ... }
@RepositoryRestResource(excerptProjection = TodoMessageSummary.class)
public interface TodoMessageRepo extends JpaRepository<Message, UUID> { ... }
@RepositoryRestResource(excerptProjection = TextMessageSummary.class)
public interface TextMessageRepo extends JpaRepository<TextMessage, UUID> { ... }
第一个问题:如何为MessageRepo定义一个摘录投影,以便为TodoMessage实体使用TodoMessageSummary,为TextMessage使用TextMessageSummary?
第二个问题:如何为另一个拥有Message字段的实体定义投影?假设你有以下内容:
@Projection(name = "summary", types = Dashboard.class)
public class DashboardSummary {
List<Message> getMessages();
}
解决:
答案 0 :(得分:1)
是的,这是可能的。我们的应用程序中有这样的子类型结构。
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, property = "type", visible = true)
public abstract class Vehicle {
protected VehicleType type;
}
public class Plane extends Vehicle {
private String title;
}
对他们的预测:
public interface VehicleProjection {
String getType();
}
@Projection(name = "default", types = Plane.class)
public interface PlaneProjection extends VehicleProjection {
String getTitle();
}
休息库:
@RepositoryRestResource(collectionResourceRel = "collectionName", path = "path",
excerptProjection = VehicleProjection.class)
public interface RestVehicleRepository<T extends Vehicle> extends MongoRepository<T, String> {
}
我们还在配置中注册了这些预测。不确定您的案例是否需要,因为我们对每个子类型都有多个投影:
@Configuration
public class CustomRestConfigurerAdapter extends RepositoryRestConfigurerAdapter {
@Override
public void configureRepositoryRestConfiguration(final RepositoryRestConfiguration config) {
config.getProjectionConfiguration().addProjection(PlaneProjection.class,
"default", Plane.class);
}
}
答案 1 :(得分:1)
诀窍是将继承用于子类型投影:
@Projection(name = "summary", types = Message.class)
public class MessageSummary {
@Value("#{target.getClass().getSimpleName()}")
String getType();
}
@Projection(name = "summary", types = TextMessage.class)
public class TextMessageSummary extends MessageSummary { ... }
@Projection(name = "summary", types = TodoMessage.class)
public class TodoMessageSummary extends MessageSummary {
Boolean getIsDone();
}
Spring REST @RepositoryRestResource
使用具体的子类型投影返回一个消息数组(isDone必须出现在TodoMessage实例中)
如果你需要在@RequestMapping
中将extendend Controller
变成 Page<Message> results = repository.findAll(predicate, pageable);
Converter<? super Message, ? extends MessageSummary> converter= l -> {
if(l instanceof TextMessage){
return projectionFactory.createProjection(TextMessageSummary.class,l);
}
else if(l instanceof TodoMessage){
return projectionFactory.createProjection(TodoMessageSummary.class,l);
}
else {
return projectionFactory.createProjection(MessageSummary.class,l);
}
};
Page<MessageSummary> projected =results.map(converter);
return pagedAssembler.toResource(projected);
,这个问题会更复杂一些,这样做我会使用下一个snnipeed:
@Value("#{target.getClass().getSimpleName()}")
String getType();
请注意,如果只需要前端的资源类型信息以便于读取(即对于POST / PUT使用具体的子类型端点)我认为并不是真的需要使用 @JsonTypeInfo < / em>因为将SpEL用于投影可以让这种类型的信息更加简单灵活:
watch i