21

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?

SOLO
  • 868
  • 9
  • 19
lapots
  • 12,553
  • 32
  • 121
  • 242
  • Possible duplicate of [Spring boot @ResponseBody doesn't serialize entity id](https://stackoverflow.com/questions/24839760/spring-boot-responsebody-doesnt-serialize-entity-id) – lcnicolau Mar 10 '19 at 00:06

7 Answers7

26

Spring Data Rest hides the ID by default, in order to have it in the JSON you have to manually configure that for your entity. Depending on your spring version you can either provide your own configuration (old):

@Configuration
public class ExposeEntityIdRestConfiguration extends RepositoryRestMvcConfiguration {

    @Override
    protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
        config.exposeIdsFor(Book.class);
    }
}

...or register a RepositoryRestConfigurer (current):

@Component
public class ExposeEntityIdRestMvcConfiguration extends RepositoryRestConfigurerAdapter {

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

See the Spring Data Rest documentation for more details.

Ralf Stuckert
  • 2,120
  • 14
  • 17
17

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

}
Domenico
  • 1,331
  • 18
  • 22
4

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);
    });
}
Liang Zhou
  • 2,055
  • 19
  • 20
3
@Component
public class RestConfig implements RepositoryRestConfigurer {

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

}
  • 2
    Thanks for contributing! You might want to add a description to your answer with references to make it clearer. See https://stackoverflow.com/help/how-to-answer for guidelines. – Jean Marois Apr 18 '20 at 17:03
3

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)));
    }
-1

This is a good way to go.

@Projection(name = "customBook", types = { Book.class }) 
public interface CustomBook {
 
    @Value("#{target.id}")
    long getId(); 
    
}

credit: https://www.baeldung.com/spring-data-rest-projections-excerpts

-1

It was helped me. Spring Data Rest hides the ID by default, in order to have it in the JSON you have to manually configure that for your entity

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – banan3'14 Aug 09 '23 at 09:48