2017-02-19 1 views
2

Est-il possible de définir différentes projections par sous-types et données de ressort REST utiliser la projection la plus concrète du type de classe?Utilisation de projections différentes pour chaque sous-type d'entité

Ce problème a été exposé sur JIRA numéro DATAREST-739 et existe également un commit de fusion mais cela n'apparaît pas sur le changelog officiel et aussi je n'ai trouvé aucune documentation ou guide pour le résoudre avec les versions actuelles.

L'échantillon de cas d'utilisation utilisé dans la question est:

@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> { ... } 

Première question: comment définir une projection d'extrait pour MessageRepo utiliser TodoMessageSummary pour les entités TodoMessage et TextMessageSummary pour TextMessage?

Deuxième problème: comment définir une projection pour une autre entité ayant un champ de message? Disons que vous avez les éléments suivants:

@Projection(name = "summary", types = Dashboard.class) 
public class DashboardSummary { 
    List<Message> getMessages(); 
} 

SOLVED:

Répondre

1

L'astuce est l'héritage d'utilisation dans les projections du sous-type:

@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(); 
} 

Le printemps REST @RepositoryRestResource retourne un tableau de messages en utilisant la projection de sous-type de béton (isDone doit être apparaître dans les instances de TodoMessage)

Cette question un peu plus complexe si vous devez fait la même dans un @RequestMapping dans une Direction générale élargie Controller, de le faire j'utilise la prochaine 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); 

Notez que si seulement besoin info type de ressource sur frontend pour en lecture seule fin (à savoir POST/PUT utiliser points d'extrémité du sous-type de béton) Je pense que n'est pas vraiment nécessaire utiliser la @JsonTypeInfo parce que l'utilisation Spel dans les projections permettent obtenir cette information de type plus simple et flexible:

@Value("#{target.getClass().getSimpleName()}") 
String getType(); 
1

Oui, il est possible. Nous avons une telle structure de sous-types dans notre application.

@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; 
} 

Les projections pour les:

public interface VehicleProjection { 
    String getType(); 
} 

@Projection(name = "default", types = Plane.class) 
public interface PlaneProjection extends VehicleProjection { 
    String getTitle(); 
} 

Et dépôt reste:

@RepositoryRestResource(collectionResourceRel = "collectionName", path = "path", 
     excerptProjection = VehicleProjection.class) 
public interface RestVehicleRepository<T extends Vehicle> extends MongoRepository<T, String> { 

} 

Aussi nous avons enregistré ces projections dans la configuration. Je ne sais pas si elle est nécessaire pour votre cas, parce que nous avons plus d'une projection pour chaque sous-type:

@Configuration 
public class CustomRestConfigurerAdapter extends RepositoryRestConfigurerAdapter { 
@Override 
     public void configureRepositoryRestConfiguration(final RepositoryRestConfiguration config) { 
      config.getProjectionConfiguration().addProjection(PlaneProjection.class, 
        "default", Plane.class); 
    } 
} 
+0

Merci pour votre réponse, ma peine était que j'ai besoin des projections de sous-type sur un mappage personnalisé de contrôleur. Je l'ai finalement résolu et pendant le processus, il m'a permis d'acquérir des connaissances sur d'autres questions utiles – pdorgambide