javaspring-mvcjpaspring-datajpa-criteria

Nested exception is java.lang.ClassCastException: java.lang.String cannot be cast


I am new to spring-data, I have this error java.lang.String cannot be cast to com.example.accessingdatamysql.User and do not know how to fix it! I add the various relevant parts of my code.

The method should output the oldest entry (via timestamp) by name.

Main.Controller

package com.example.accessingdatamysql;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller 
@RequestMapping(path="/demo") 
public class MainController {
  @Autowired 
         
  private UserRepository userRepository;

  @Transactional
  @PostMapping(path="/add")
  public @ResponseBody String addNewUser (@RequestParam String name,
          @RequestParam String email,@RequestParam String surname) 
  {
      User n = new User();
      n.setName(name);
      n.setSurname(surname);
      n.setEmail(email);
      userRepository.create(n);
      return "Saved";
  }

  @GetMapping(path="first")
  User one(@RequestParam String name) {
      return userRepository.findFirstByName(name);
  }
}  

User.java

package com.example.accessingdatamysql;

import java.sql.Timestamp;
import java.time.Instant;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity 
public class  User {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Integer id;
 
  public String name;

  private String email;
  
  private String surname;
  
  @Column(name="stmp", columnDefinition = "TIMESTAMP (6)")
  Timestamp timestamp = Timestamp.from(Instant.now());

  public void setTimestamp(Timestamp timestamp) {
      this.timestamp = timestamp;
  }

  public Timestamp getTimestamp() {
      return timestamp;
  }

  public String getSurname() {
      return surname;
  }
 
  public void setSurname(String surname) {
      this.surname = surname;
  }
 
  public Integer getId() {
      return id;
  }

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

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }

  public String getEmail() {
      return email;
  }

  public void setEmail(String email) {
      this.email = email;
  }
}

RepoImpl.java

package com.example.accessingdatamysql;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.springframework.stereotype.Component;

@Component
public class UserRepositoryImpl implements UserRepository {
    
    private final EntityManager em;
    
    public UserRepositoryImpl(EntityManager entityManager) {
        this.em = entityManager;
    }

    @Override
    public User findFirstByName(String name) {
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<User> criteria = builder.createQuery(User.class);
        Root<User> root = criteria.from(User.class);
        criteria.select(root.get("name"));
        criteria.orderBy(builder.asc(root.get("timestamp")));
        TypedQuery<User> query = em.createQuery(criteria).setMaxResults(1);
        return query.getSingleResult();
    }
    
    @Override
//  per la creazione//
    public void create(User entity) {
        em.persist(entity); 
    }   
}

ERROR

 [Request processing failed; nested exception is java.lang.ClassCastException: java.lang.String cannot be cast to com.example.accessingdatamysql.User] with root cause
java.lang.ClassCastException: java.lang.String cannot be cast to com.example.accessingdatamysql.User
        at com.example.accessingdatamysql.UserRepositoryImpl.findFirstByName(UserRepositoryImpl.java:35) ~[classes!/:0.0.1-SNAPSHOT]

Solution

  • If you meant to find User by name, you should have set the filter parameter not in criteria.select but in criteria.where:

    public User findFirstByName(String name) {
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<User> criteria = builder.createQuery(User.class);
        Root<User> root = criteria.from(User.class); // root is User
        criteria.select(root).where(builder.equal(root.get("name"), name));
        criteria.orderBy(builder.asc(root.get("timestamp")));
        TypedQuery<User> query = em.createQuery(criteria).setMaxResults(1);
        return query.getSingleResult();
    }
    

    While criteria.select(root.get("name")); implies that only column "name" is selected and returned, that is the name of the first user should be returned.

    If such information is needed, it may be retrieved in the following way:

    public String findFirstUserName() {
        CriteriaBuilder builder = em.getCriteriaBuilder();
        CriteriaQuery<String> criteria = builder.createQuery(String.class);
        Root<User> root = criteria.from(User.class); // root is User
        criteria.select(root.get("name"));  // getting name 
        criteria.orderBy(builder.asc(root.get("timestamp"))); // of the first/earliest user 
        TypedQuery<String> query = em.createQuery(criteria).setMaxResults(1);
        return query.getSingleResult();
    }