2

I'm attempting to get Spring Data Rest to work with my entities. I implemented the repository and can see the list of available ones when requesting localhost:8080.

However, when attempting to execute any of the repository queries via the REST interface (e.g. findAll() via localhost:8080/users), the response is empty. I traced the issue to the following:

There is a call to org.springframework.data.jpa.mapping.JpaPersistentEntityImpl.getIdProperty() (method implemented in base class BasicPersistentEntity) which returns null. The call is made from PersistentEntityResourceAssembler.getSelfLinkFor(..). A null Id property then causes a null pointer exception further down the stack trace, however this null pointer exception never surfaces to the app, apart from a debug log saying "null ModelAndView".

It turns out that the only reason the getIdProperty() return null is because I am not using FIELD annotations, but rather method annotation. So the @Id annotation is applied on the getter getUserId() and not on the filed userId.

I don't believe this is the correct behaviour. Either JpaPersistentEntityImpl.getIdProperty() is not properly configured to return the correct ID or PersistentEntityResourceAssembler.getSelfLinkFor(..) should use a different method for getting the id. Unless thes system does not support entities that use method annotations, but I always though that its a valid JPA spec.

Anyone have any ideas on how to resolve this issue while maintaining the annotated methods approach (rather than annotated fields).

Also, anyone know how to better configure the system for better exception handling, so that such erors do not degrade so quietly?


More inconsistencies between fields and methods:

I also discovered that setters and getter must be implemented for all fields in order for them to render in the resulting json. However for fields that are non-basic, (e.g. managed beans), the names are fetched from the field names not the properties (as in the basic ones).

e.g.:

  @Entity
  class  User
  {

    @Id
    long Id;
    String firstNameField;
    String lastNameField;
    Account accountField;   //a managed bean

    long getId() ...
    String getFirstName() ...
    String getLastName() ....
    Account getAccount()  ....

}

Results in the following json:

    {
        firstName: "..."
        lastName: "....."
        accountField:  ".....link..."
      }

not that the first two fields names correspond to the method name while the managed bean field corresponds to the field name.

(I omitted the setters and most the entity annotations for brevity, but they are there and correct)


ok here is a concrete example:

/** */

@Entity @Table (name = "USERS", schema = "CARS", catalog = "") public class User {

private int userId;
private String firstName;
private String lastName;
private String password;
private String email;

//todo: Ugh, this is odd...Spring data rest does not seem to render links to ManyToMany properties using method annotation...must add it to the field declaration...removing this from here will result in removing the property from the rest response...needs further investigation
@ManyToMany
@JoinTable (name = "USER_ROLE",
            joinColumns = @JoinColumn(updatable = false, insertable = false, name = "USER_ID", referencedColumnName = "USER_ID"),
            inverseJoinColumns = @JoinColumn(updatable = false, insertable = false, name = "ROLE_ID", referencedColumnName = "ROLE_ID"))
private Collection<Role> roles;



@Id
@Column (name = "USER_ID")
public int getUserId()
{
    return userId;
}


public void setUserId(int inUserId)
{
    userId = inUserId;
}


@Basic
@Column (name = "FIRST_NAME")
public String getFirstName()
{
    return firstName;
}


public void setFirstName(String inFirstName)
{
    firstName = inFirstName;
}


@Basic
@Column (name = "LAST_NAME")
public String getLastName()
{
    return lastName;
}


public void setLastName(String inLastName)
{
    lastName = inLastName;
}


@Basic
@Column (name = "PASSWORD")
public String getPassword()
{
    return password;
}


public void setPassword(String inPassword)
{
    password = inPassword;
}



@Override
public boolean equals(Object o)
{
    ...........
}


@Override
public int hashCode()
{
    ......
}


@ManyToMany
@JoinTable (name = "USER_ROLE",
           joinColumns = @JoinColumn(updatable = false, insertable = false, name = "USER_ID", referencedColumnName = "USER_ID"),
           inverseJoinColumns = @JoinColumn(updatable = false, insertable = false, name = "ROLE_ID", referencedColumnName = "ROLE_ID"))
private Collection<Role> getRoles()
{
    return roles;
}


private void setRoles(Collection<Role> inRoles)
{
    roles = inRoles;
}

@Override public boolean equals(Object o) { ........... }

@Override
public int hashCode()
{
    ......
}

}

1
  • If you look at the source code, then you'll see that it doesn't matter where you place the @Id annotation. And it indeed works for me both ways. It would be helpful to post your concrete example. And what exactly are non-basic fields? Commented Sep 12, 2014 at 20:36

1 Answer 1

1

You need to implement the getters and setters and annotate the primary key. There are several good examples in the guides.

Sign up to request clarification or add additional context in comments.

1 Comment

Obviously. And I am. I am not sure if you read my whole post thoroughly, but the issue is the between annotations of fields vs annotations of methods (sometime the former is required using spring jpa, but this does not accord to jpa specs). Further, the names are extracted sometime from fields and sometime from methods, inconsistently.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.