对每个实体子类型使用不同的投影
Using different projection for each entity subtype
是否可以通过子类型和 Spring 数据 REST 定义不同的投影
使用关于 class 类型的最具体投影?
此问题已在 JIRA 问题 DATAREST-739 and also exists a merge commit but this not appears on official 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();
}
已解决:
是的,这是可能的。我们的应用程序中有这样的 sub-types 结构。
@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> {
}
我们还在配置中注册了这些投影。不确定您的情况是否需要它,因为我们对每个 sub-type:
有不止一个投影
@Configuration
public class CustomRestConfigurerAdapter extends RepositoryRestConfigurerAdapter {
@Override
public void configureRepositoryRestConfiguration(final RepositoryRestConfiguration config) {
config.getProjectionConfiguration().addProjection(PlaneProjection.class,
"default", Plane.class);
}
}
诀窍是在子类型投影中使用继承:
@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
returns 使用具体子类型投影的消息数组(isDone 必须出现在 TodoMessage 实例中)
这个问题有点复杂,如果你需要将相同的扩展@RequestMapping
变成Controller
,为此我使用下一个snnipeed:
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);
请注意,如果前端只需要 资源类型信息 用于只读目的(即 POST/PUT 使用具体的子类型端点),我认为这并不是真正需要使用的@JsonTypeInfo 因为在投影中使用 SpEL 可以更轻松、更灵活地获取此类型信息:
@Value("#{target.getClass().getSimpleName()}")
String getType();
是否可以通过子类型和 Spring 数据 REST 定义不同的投影 使用关于 class 类型的最具体投影?
此问题已在 JIRA 问题 DATAREST-739 and also exists a merge commit but this not appears on official 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();
}
已解决:
是的,这是可能的。我们的应用程序中有这样的 sub-types 结构。
@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> {
}
我们还在配置中注册了这些投影。不确定您的情况是否需要它,因为我们对每个 sub-type:
有不止一个投影@Configuration
public class CustomRestConfigurerAdapter extends RepositoryRestConfigurerAdapter {
@Override
public void configureRepositoryRestConfiguration(final RepositoryRestConfiguration config) {
config.getProjectionConfiguration().addProjection(PlaneProjection.class,
"default", Plane.class);
}
}
诀窍是在子类型投影中使用继承:
@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
returns 使用具体子类型投影的消息数组(isDone 必须出现在 TodoMessage 实例中)
这个问题有点复杂,如果你需要将相同的扩展@RequestMapping
变成Controller
,为此我使用下一个snnipeed:
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);
请注意,如果前端只需要 资源类型信息 用于只读目的(即 POST/PUT 使用具体的子类型端点),我认为这并不是真正需要使用的@JsonTypeInfo 因为在投影中使用 SpEL 可以更轻松、更灵活地获取此类型信息:
@Value("#{target.getClass().getSimpleName()}")
String getType();