spring-projects / spring-projects/spring-data-rest

Nested projection of abstract entities does not show links [DATAREST-1002]

Open
#1,365 0 comments 0 reactions 1 assignee View on GitHub

@odrotbohm is already working on this.

Since Dec 31, 2020.

type: bug
Dominant language
Java
Stars
958
Forks
568
PR merge metrics
No merged PRs in 30d

Description

Benjamin Legendre opened DATAREST-1002 and commented

Despite it does not seems to be documented elsewhere, the common method to make "links.self.href" for nested inlined entities in projection to appear is to make themselves projections. It is well explained here: http://stackoverflow.com/a/38165158/5276344 and i confirm it works.

But not when the nested entity is a Parent abstract entity in a inheritance tree.

Given theses entity/repository/projection (assessors removed for clarity):

@Entity
@Table(name="items")
@DiscriminatorColumn(name="type")
@DiscriminatorOptions(force=true)
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
public abstract class AbstractItem {

    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    @ManyToOne
    @JoinColumn(name="some_entity_id", nullable=false)
    private SomeEntity someEntity;
}

@Entity
@DiscriminatorValue(value="concrete-item-1")
public class ConcreteItemOne extends AbstractItem{
    
    private String itemOneField;
}

@Entity
@DiscriminatorValue(value="concrete-item-2")
public class ConcreteItemTwo extends AbstractItem{

    private String itemTwoField;
}

@Entity
public class SomeEntity {

    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    @OneToMany(mappedBy="someEntity", orphanRemoval=true, cascade = CascadeType.ALL)
    private List<AbstractItem> items = new ArrayList<>();

    @OneToMany(mappedBy="someEntity", orphanRemoval=true, cascade = CascadeType.ALL)
    private List<WithoutInheritanceEntity> withoutInheritanceEntities = new ArrayList<>();

@Entity
public class WithoutInheritanceEntity {

    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    @ManyToOne
    @JoinColumn(name="some_entity_id", nullable=false)
    private SomeEntity someEntity;
}

public interface AbstractItemRepository 
    extends CrudRepository<AbstractItem, Integer> {
}

public interface SomeEntityRepository 
    extends CrudRepository<SomeEntity, Integer> {
}

public interface WithoutInheritanceEntityRepository
    extends CrudRepository<WithoutInheritanceEntity, Integer> {
}

@Projection(name = "abstractItemProjection", types = { AbstractItem.class })
public interface AbstractItemProjection {

    String getName();    

}

@Projection(name = "someEntityProjection", types = { SomeEntity.class })
public interface SomeEntityProjection {

    String getName();

    List<AbstractItemProjection> getItems();

    List<WithoutInheritanceEntityProjection> getWithoutInheritanceEntities();
}

@Projection(name = "withoutInheritanceEntityProjection", types = { WithoutInheritanceEntity.class })
public interface WithoutInheritanceEntityProjection {

    String getName();

}

When executing this test case:

this.mockMvc.perform(get("/someEntities/1?projection=someEntityProjection")
    .accept(MediaType.parseMediaType("application/json;charset=UTF-8")))
    .andDo(MockMvcResultHandlers.print())
    .andExpect(jsonPath("$.withoutInheritanceEntities[0]._links.self.href").exists())
    .andExpect(jsonPath("$.items[0]._links.self.href").exists());

The returned json is:


{
  "items" : [ {
    "name" : "item-1"
  }, {
    "name" : "item-2"
  } ],
  "withoutInheritanceEntities" : [ {
    "name" : "without-inheritance-entity-1",
    "_links" : {
      "self" : {
        "href" : "http://localhost/withoutInheritanceEntities/1{?projection}",
        "templated" : true
      },
      "someEntity" : {
        "href" : "http://localhost/withoutInheritanceEntities/1/someEntity"
      }
    }
  }, {
    "name" : "without-inheritance-entity-1",
    "_links" : {
      "self" : {
        "href" : "http://localhost/withoutInheritanceEntities/2{?projection}",
        "templated" : true
      },
      "someEntity" : {
        "href" : "http://localhost/withoutInheritanceEntities/2/someEntity"
      }
    }
  } ],
  "name" : "some-entity-1",
  "_links" : {
    "self" : {
      "href" : "http://localhost/someEntities/1"
    },
    "someEntity" : {
      "href" : "http://localhost/someEntities/1{?projection}",
      "templated" : true
    },
    "withoutInheritanceEntities" : {
      "href" : "http://localhost/someEntities/1/withoutInheritanceEntities"
    },
    "items" : {
      "href" : "http://localhost/someEntities/1/items"
    }
  }
}

As you can see , items in 'items' array have no links (nested abstract entity) but items in 'withoutInheritanceEntities' array have links (simple nested entity without inheritance).

The test result:

No value at JSON path "$.items[0]._links.self.href", exception: Missing property in path $['items'][0]['_links']

The complete test case can be found as a Maven project on the attached zip. Simply run mvn test


Affects: 2.6 GA (Ingalls)

Attachments:

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.