Экспортировать все идентификаторы при использовании Spring Data Rest
Я хотел бы предоставить все идентификаторы, используя интерфейс Spring Rest.
Я знаю, что по умолчанию такой идентификатор не будет отображаться через интерфейс rest:
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(unique=true, nullable=false)
private Long id;
Я знаю, что могу использовать это, чтобы предоставить идентификатор для User
:
@Configuration
public class RepositoryConfig extends RepositoryRestMvcConfiguration {
@Override
protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(User.class);
}
}
Но есть ли простой способ выставить все идентификаторы без ручного ведения списка в этом методе configureRepositoryRestConfiguration
?
Ответы
Ответ 1
В настоящее время нет способа сделать это с помощью SDR. Эта проблема на трекерах SDR Jira дает некоторое объяснение, почему это невозможно (и, возможно, не должно) быть возможным.
Аргумент в основном состоит в том, что, поскольку идентификаторы уже содержатся в ссылках self
в ответе, вам не нужно раскрывать их как свойства самого объекта.
Тем не менее, вы можете использовать отражение для извлечения всех классов с аннотацией javax.persistence.Id
, а затем вызвать RepositoryRestConfiguration#exposeIdsFor(Class<?>... domainTypes)
.
Ответ 2
Я обнаружил, что если вы назовете поле @Id
'Id
', оно будет отображаться в JSON, если у вас есть публичный getter для Id
. Идентификатор будет отображаться как ключ JSON под названием "Id
"
Например: @Id @Column(name="PERSON_ROLE_ID") private Long Id;
Это также работает для полей @EmbeddedId
, называемых 'Id
', и пока он имеет публичный getter. В этом случае поля Id будут отображаться как объект JSON.
Например: @EmbeddedId private PrimaryKey Id;
Удивительно, что это чувствительно к регистру, вызов id 'Id
' не работает, хотя это было бы более условное имя для поля Java.
Я должен сказать, что я обнаружил это полностью случайно, поэтому я не знаю, является ли это принятым соглашением или будет работать с предыдущими или будущими версиями Spring данных и REST. Поэтому я включил соответствующие части моего maven mom только в том смысле, что он восприимчив к версиям...
<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>
Ответ 3
Если вы хотите открыть поле id для всех ваших классов сущностей:
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]));
}
}
Ответ 4
Вы можете использовать этот метод, чтобы найти все классы @Entity
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;
}
затем, чтобы вывести идентификаторы для всех ваших классов сущностей:
@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);
}
}
}
}
Ответ 5
Возможно, вы можете попробовать включить все поля id. Я еще не пробовал, но буду держать в курсе.
public class ExposeAllRepositoryRestConfiguration extends RepositoryRestConfiguration {
@Override
public boolean isIdExposedFor(Class<?> domainType) {
return true;
}
}
Выдержка из этой ссылки
Ответ 6
Вы можете добавить все классы сущностей через exposeIdsFor. Замените "db.entity" на пакет, в который вы положили свои объекты.
@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);
}
}
ClassTool - это моя настраиваемая функция для получения класса из данного пакета, вы можете написать сами.
Ответ 7
Вот что отлично сработало для меня (источник здесь):
@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);
}
}
}
}
Он находит все beans с аннотацией @Entity и предоставляет их.
Ответ 8
Попробуйте эту конфигурацию. Это прекрасно работает для меня.
@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());
}
});
}
}
Ответ 9
Пожалуйста, найдите простое решение для этого, избегая поиска связанных сущностей.
@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;
}
}
}
Ответ 10
Следующий фрагмент кода выглядит красивее:
.exposeIdsFor(entityManager.getMetamodel().getEntities().stream().map(entityType -> entityType.getJavaType()).toArray(Class[]::new))
Ответ 11
Вы можете попробовать это решение: - Сначала импортируйте библиотеку отражений в ваш файл POM:
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
- Затем измените свой класс RepositoryConfig на:
@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;
}
}
Измените com.example.entity на ваш пакет Entity, и все готово. Удачи!