Search code examples
javaspring-securityspring-data

findById(ID) in CrudRepository - attempting to use incompatible return type


I have defined message entity

@Entity
public class Message {
    @Id
    @GeneratedValue()
    private long id;

    @OneToOne
    @NotNull
    private User user;

    @NotEmpty(message = "text is required")
    private String text;

    @NotEmpty(message = "title is required")
    private String title;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public long getId() {
        return id;
    }

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

and CrudRepository

public interface MessageRepository extends CrudRepository<Message, Long> {


    @PostAuthorize("hasPermission(returnObject, 'message')")
    Message findById(Long id);

    Iterable<Message> findByUserId(Long id);

    @PostAuthorize("hasPermission(returnObject, 'privateMessage')")
    Message findOne(Long id);

}

I get the following error Error

When I use

 @PostAuthorize("hasPermission(returnObject, 'message')")
  Optional<Message> findById(Long id);

still doesn't work. I get, that the "Message message = messageRepository.findById(id);" cannot be converted and i should change variable "message" type to the "Optional<"Message>"

When I do that, I get following error:

Error creating bean with name 'defaultController': Unsatisfied dependency expressed through field 'messageRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'messageRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract com.example.chapter5.data.Message com.example.chapter5.data.MessageRepository.findOne(java.lang.Long)! No property findOne found for type Message!

Can someone suggest an alternative solution? Thanks


Solution

  • Spring data will convert your method names to actual database queries. But this doesn't happen magically. Of course spring does magic, But you have to follow the syntax.

    In your first method, Message findById(Long id); Spring understands that you need Message object and you need to find that by message_id. This is converted it to somewhat like the following.

    select msg from Message msg where msg.id = ?1;

    ?1 will be replaced by your method argument.

    If you do not wish Spring to generate the query for you, then you have to use @Query and provide your own custom query.(Method name does not matter in this case.)

    you can achieve this as mentioned here.

    Now, coming back to your error, Spring is not able to understand your method Message findOne(Long id);. Because it is expecting the syntax findBy.

    You can find the valid method names from spring documentations.

    What I don't understand is, how are methods Message findById(Long id); and Message findOne(Long id); different. I suppose they both try to get Message from messageId.