Return IDs in JSON response from Spring Data REST

Viewed 18258

I've got an entity

@Entity
@Table(name = "books")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    @Column(name = "id", unique = true, nullable = false)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

I initialize it like this

@PostConstruct
public void init() {
    List<String> newFiles = this.listFiles();
    newFiles.forEach(filename -> {
        Book book = new Book();
        book.setName(filename);

        dbRepository.save(book);
    });
}

If I set the result of save to an instance of Book, I can get the id and it is not null—so id is created fine.

I defined a repository

@RepositoryRestResource
public interface IBooksRepository extends CrudRepository<Book, Long> {
}

which I'd like to use to get and set data into the books table in the database.

When I try to access my repository rest using curl localhost:8080/books, I get this response

{
   "_embedded":{
      "books":[
         {
            "name":"simple-file.txt",
            "_links":{
               "self":{
                  "href":"http://localhost:8080/books/1"
               },
               "book":{
                  "href":"http://localhost:8080/books/1"
               }
            }
         }
      ]
   },
   "_links":{
      "self":{
         "href":"http://localhost:8080/books"
      },
      "profile":{
         "href":"http://localhost:8080/profile/books"
      }
   }
}

The books element returns name only. How can I make it return id too, on the same level as name?

6 Answers

The accepted answer overrides a deprecated method. Here's the updated version:

@Component
public class RestConfig implements RepositoryRestConfigurer {

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
        config.exposeIdsFor(Book.class);
    }
}

An alternative approach is to implement RepositoryRestConfigurer in your @SpringBootApplication annotated class:

@SpringBootApplication
public class MyApplication implements RepositoryRestConfigurer {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
        config.exposeIdsFor(Book.class);
    }

}
@Component
public class RestConfig implements RepositoryRestConfigurer {

    @Override
      public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(Book.class);
        //config.exposeIdsFor(Library.class);
      }

}

This is a solution which works for all entities

    @Autowired
    private EntityManager entityManager;
    
    @Bean
    public RepositoryRestConfigurer repositoryRestConfigurer() {
        return RepositoryRestConfigurer.withConfig(config -> config.exposeIdsFor(entityManager.getMetamodel().getEntities().stream().map(Type::getJavaType).toArray(Class[]::new)));
    }

There is now a static method RepositoryRestConfigurer.withConfig that does the same thing as above. See javadoc:

Convenience method to easily create simple {@link RepositoryRestConfigurer} instances that solely want to tweak the {@link RepositoryRestConfiguration}.

I found the usage in one of their integration tests

So the following approach would be more up to date as of now:

@Bean
public RepositoryRestConfigurer repositoryRestConfigurer()
{
    return RepositoryRestConfigurer.withConfig(config -> {
        config.exposeIdsFor(Book.class);
    });
}
Related