web-dev-qa-db-fra.com

Afficher tous les ID lors de l'utilisation de Spring Data Rest

Je voudrais exposer tous les ID à l'aide d'une interface Spring Rest.

Je sais que par défaut, un ID comme celui-ci ne sera pas exposé via l'interface de repos:

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(unique=true, nullable=false)
    private Long id;

Je suis conscient que je peux l'utiliser pour exposer l'ID de User:

@Configuration
public class RepositoryConfig extends RepositoryRestMvcConfiguration {
    @Override
    protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(User.class);
    }
}

Mais existe-t-il un moyen simple d'exposer tous les ID sans gérer manuellement une liste dans cette méthode configureRepositoryRestConfiguration?

22
Baiteman

Actuellement, il n'y a aucun moyen de le faire fourni par SDR. Ce problème sur le traqueur SDR Jira explique pourquoi ce n'est pas (et ne devrait peut-être pas) être possible.

L'argument est essentiellement que, puisque les ID sont déjà contenus dans les liens self dans la réponse, vous n'avez pas besoin de les exposer en tant que propriétés de l'objet lui-même.

Cela dit, vous pourrez peut-être utiliser la réflexion pour récupérer toutes les classes qui ont une annotation javax.persistence.Id, Puis appeler RepositoryRestConfiguration#exposeIdsFor(Class<?>... domainTypes).

11
Justin Lewis

Si vous souhaitez exposer le champ id pour toutes vos classes d'entités:

import Java.util.stream.Collectors;

import javax.persistence.EntityManager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;

@Configuration
public class MyRepositoryRestConfigurerAdapter extends RepositoryRestConfigurerAdapter {

    @Autowired
    private EntityManager entityManager;

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(entityManager.getMetamodel().getEntities().stream().map(e -> e.getJavaType()).collect(Collectors.toList()).toArray(new Class[0]));
    }

}
15
mekazu

J'ai découvert que si vous nommez le champ @Id 'Id', il s'affichera dans le JSON si vous avez un getter public pour le Id. L'ID apparaîtra comme une clé JSON appelée 'id'

Par exemple: @Id @Column(name="PERSON_ROLE_ID") private Long Id;

Cela fonctionne également pour les champs @EmbeddedId Appelés 'Id' aussi longtemps qu'il a un getter public. Dans ce cas, les champs de l'ID apparaîtront comme un objet JSON.

Par exemple: @EmbeddedId private PrimaryKey Id;

Étonnamment, cela est sensible à la casse, l'appel de l'id 'id' ne fonctionne pas même s'il s'agit d'un nom plus conventionnel pour un champ Java.

Je dois dire que j'ai découvert cela complètement par accident, donc je ne sais pas s'il s'agit d'une convention acceptée ou fonctionnera avec les versions précédentes ou futures de Spring Data et REST. Par conséquent, j'ai inclus les parties pertinentes de mon pom maven au cas où il serait sensible aux versions ...

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <Java.version>1.8</Java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>com.Oracle</groupId>
        <artifactId>ojdbc7</artifactId>
        <version>12.1.0.2</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
</dependencies>
15
Mark

Vous pouvez utiliser cette méthode pour trouver tous les @Entity classes de EntityManagerFactory:

private List<Class<?>> getAllManagedEntityTypes(EntityManagerFactory entityManagerFactory) {
    List<Class<?>> entityClasses = new ArrayList<>();
    Metamodel metamodel = entityManagerFactory.getMetamodel();
    for (ManagedType<?> managedType : metamodel.getManagedTypes()) {
        Class<?> javaType = managedType.getJavaType();
        if (javaType.isAnnotationPresent(Entity.class)) {
            entityClasses.add(managedType.getJavaType());
        }
    }
    return entityClasses;
}

puis, pour exposer les ID de toutes vos classes d'entités:

@Configuration
public class RestConfig extends RepositoryRestMvcConfiguration {

    @Bean
    public RepositoryRestConfigurer repositoryRestConfigurer(EntityManagerFactory entityManagerFactory) {
        List<Class<?>> entityClasses = getAllManagedEntityTypes(entityManagerFactory);

        return new RepositoryRestConfigurerAdapter() {

            @Override
            public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
                for (Class<?> entityClass : entityClasses) {
                    config.exposeIdsFor(entityClass);
                }
            }
    }
}
2
Dario Seidl

Essayez cette configuration. Cela fonctionne parfaitement bien pour moi.

@Configuration
public class RestConfiguration extends RepositoryRestConfigurerAdapter{

      @PersistenceContext
      private EntityManager entityManager;

      @Override
      public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
           //TODO: Expose for specific entity!
           //config.exposeIdsFor(Officer.class);
           //config.exposeIdsFor(Position.class);

           //TODO: Expose id for all entities!
           entityManager.getMetamodel().getEntities().forEach(entity->{
                try {
                     System.out.println("Model: " + entity.getName());
                     Class<? extends Object> clazz = Class.forName(String.format("yourpackage.%s", entity.getName()));
                     config.exposeIdsFor(clazz);
                } catch (Exception e) {
                     System.out.println(e.getMessage());
                }
            });
    }
}
1
Phearun Rath

Vous pouvez ajouter toutes vos classes d'entités par exposeIdsFor. Remplacez "db.entity" pour whick package que vous mettez vos entités.

@Configuration
public class CustomRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter {
    Logger logger = Logger.getLogger(this.getClass());

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        Set<String> classNameSet = ClassTool.getClassName("db.entity", false);
        for (String className : classNameSet) {
            try {
                config.exposeIdsFor(Class.forName(className));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        logger.info("exposeIdsFor : " + classNameSet);
    }
}

Le ClassTool est ma fonction personnalisée pour obtenir la classe d'un package donné, vous pouvez écrire par vous-même.

0
kidfruit

Voici ce qui a parfaitement fonctionné pour moi ( source ici ):

@Configuration
public class RepositoryRestConfig extends RepositoryRestConfigurerAdapter {

  @Override
  public void configureRepositoryRestConfiguration(final RepositoryRestConfiguration config) {

    final ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(
        false);
    provider.addIncludeFilter(new AnnotationTypeFilter(Entity.class));

    final Set<BeanDefinition> beans = provider.findCandidateComponents("com.your.domain");

    for (final BeanDefinition bean : beans) {
      try {
        config.exposeIdsFor(Class.forName(bean.getBeanClassName()));
      } catch (final ClassNotFoundException e) {
        // Can't throw ClassNotFoundException due to the method signature. Need to cast it
        throw new IllegalStateException("Failed to expose `id` field due to", e);
      }
    }
  }
}

Il trouve tous les beans avec l'annotation @Entity et les expose.

0
Stephan

Vous pouvez probablement essayer ceci pour inclure tous les champs id. Je ne l'ai pas encore essayé, mais je resterai au courant.

 public class ExposeAllRepositoryRestConfiguration extends RepositoryRestConfiguration {
    @Override
    public boolean isIdExposedFor(Class<?> domainType) {
        return true;
        }
    }

Extrait de ce lien

0
raksja

Le code suivant semble plus joli:

.exposeIdsFor(entityManager.getMetamodel().getEntities().stream().map(entityType -> entityType.getJavaType()).toArray(Class[]::new))
0
Francois Gengler

Vous pouvez essayer avec cette solution: - Première importation réflexions bibliothèque dans votre fichier POM:

<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.11</version>
</dependency>

- Modifiez ensuite votre classe RepositoryConfig en:

@Configuration
public class RepositoryConfig extends RepositoryRestMvcConfiguration {
    @Override
    protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        Reflections reflections = new Reflections("com.example.entity");
        Set<Class<?>> idExposedClasses = reflections.getTypesAnnotatedWith(Entity.class, false);
        idExposedClasses.forEach(config::exposeIdsFor);
        return config;
    }
}

Modifiez "com.example.entity" en votre Package d'entité et vous êtes prêt à partir. Bonne chance!

0
Terry

Veuillez trouver une solution simple pour cela, en évitant de trouver des entités liées.

@Component
public class EntityExposingIdConfiguration extends RepositoryRestConfigurerAdapter {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        try {
            Field exposeIdsFor = RepositoryRestConfiguration.class.getDeclaredField("exposeIdsFor");
            exposeIdsFor.setAccessible(true);
            ReflectionUtils.setField(exposeIdsFor, config, new ListAlwaysContains());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

    class ListAlwaysContains extends ArrayList {

        @Override
        public boolean contains(Object o) {
            return true;
        }
    }
}
0
David B.