aycanadal
aycanadal

Reputation: 1146

Spring Data Neo4j polymorphic association appears embedded

I'm having a problem exposing a relationship to a sub-type via rest. I have an abstract class called Page:

@NodeEntity
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "category", visible = true)
@JsonSubTypes({ @Type(value = Musician.class), @Type(value = Book.class),
        @Type(value = Song.class) })
public abstract class Page extends BaseEntity{

    @Fetch
    @CreatedBy
    private User creator;

    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @GraphProperty(propertyType = Long.class)
    @CreatedDate private LocalDateTime timeCreated;

    @NotEmpty
    @Size(min = 1, max = 160)
    @Indexed(indexType = IndexType.FULLTEXT, indexName = "search")
    private String screenname;

    @Fetch
    @RelatedTo(type = "CHANNEL")
    private Channel channel = new Channel();

    public Channel getChannel() {
        return channel;
    }

    public void setChannel(Channel channel) {
        this.channel = channel;
    }

    public String getScreenname() {
        return screenname;
    }

    public void setScreenname(String screenname) {
        this.screenname = screenname;
    }

    // This is to work around the bug where type name is not exported by SDR.
    @JsonGetter(value = "category")
    public String getType() {
        return this.getClass().getSimpleName();
    }

    public User getCreator() {
        return creator;
    }

    public void setCreator(User creator) {
        this.creator = creator;
    }

    public LocalDateTime getTimeCreated() {
        return timeCreated;
    }

    public void setTimeCreated(LocalDateTime timeCreated) {
        this.timeCreated = timeCreated;
    }

}

Two subtypes Song and Musician:

@NodeEntity
@JsonTypeName("Song")
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="category", visible=true)
public class Song extends Page {

    @Fetch
    @RelatedTo(type = "SINGER")
    private Musician singer;

    public Musician getSinger() {
        return singer;
    }

    public void setSinger(Musician singer) {
        this.singer = singer;
    }

}

and

@NodeEntity
@JsonTypeName("Musician")
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=JsonTypeInfo.As.PROPERTY, property="category", visible=true)
public final class Musician extends Page {

}

And a repository that is supposed to manage all subtypes of Page:

@RepositoryRestResource(collectionResourceRel = "pages", path = "pages")
public interface PageRepository extends PagingAndSortingRepository<Page, Long> {

    org.springframework.data.domain.Page<Musician> findMusicianByScreennameLike(@Param("0") String screenname, Pageable page);

}

When I get a Song instance from my api the json looks like:

{
  "uuid" : "ee9daf8b-4285-45bb-a583-e37f54284c43",
  "timeCreated" : null,
  "screenname" : "songtest",
  "singer" : null,
  "id" : 213,
  "category" : "Song",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/api/pages/213"
    },
    "channel" : {
      "href" : "http://localhost:8080/api/pages/213/channel"
    },
    "creator" : {
      "href" : "http://localhost:8080/api/pages/213/creator"
    }
  }
}

The problem is that the singer field appears embedded. And I can not associate an existing musician to this singer field. When I try to assign a uri of an existing musician to the singer field, it complains that it can not convert from String to Musician. If I provide json instead of uri, then it creates a new musician with same field values. So when the subtype Musician is referenced from an entity, it is treated as if it is not managed by it's supertype's repository. How can I make it so that the singer is exported like other associated top level resources under the links section and can be assigned an existing resource by accepting a uri? Or is it not possible at all?

Upvotes: 1

Views: 402

Answers (1)

TLA
TLA

Reputation: 166

I believe you'll need separate repositories for Musician, Book, and Song for Spring Data Rest to correctly determine the relationships between the entities. Once that's fixed, it should behave the way you expect - returning links for embedded entities instead of JSON, and accepting uri's when posting embedded entities.

You might want to take a look at this answer for an idea of how to handle inheritance in your Repository definitions:

https://stackoverflow.com/a/27549198/4601679

Upvotes: 2

Related Questions