【问题标题】:Class Cast Exception - Hibernate mapping + Spring MVC类转换异常 - Hibernate 映射 + Spring MVC
【发布时间】:2017-11-20 09:10:51
【问题描述】:

早上好, 我正在开发一个跟踪业务指标的应用程序。该数据库的构建不常见,这会导致复杂的查询(在我的级别)和复杂的映射。你能帮我看看下面的堆栈跟踪吗:

Caused by: java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to fr.alteca.outilindicateurs.entityRedmine.Issues
at fr.alteca.outilindicateurs.controller.IssuesRESTController.init(IssuesRESTController.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:365)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:310)
at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:133)
... 44 more

数据库查询(MySQL),按预期工作:

SELECT issues.id, 
max(CASE WHEN custom_fields.name='Date de résolution'
   THEN custom_values.value 
 ELSE '-'
END) AS date_resolution ,
max(CASE WHEN custom_fields.name='Date d\'ouverture'
   THEN custom_values.value
ELSE '-'
END ) AS date_ouverture
    FROM redmine_tma_ibp.issues
join custom_values 
    on issues.id = custom_values.customized_id
join custom_fields 
    on custom_values.custom_field_id = custom_fields.id
join enumerations 
    on enumerations.id=issues.priority_id

where (enumerations.type="IssuePriority" and (enumerations.position=1 or enumerations.position=2))
    and (status_id=3 or status_id=5)
    and (custom_fields.name = "Date d'ouverture" or custom_fields.name="Date de résolution")
    and str_to_date(custom_values.value, '%d/%m/%Y %H:%i') > date('2016-01-01')
    group by issues.id

此请求的 HQL 翻译(待签出):

public static  String GET_RECORDS_FOR_M1 = 
        "Select  i, max(case when cf.name=:date_denom then cv.value else    null end) as date_ouverture FROM Issues i, CustomValues cv, CustomFields cf,    Enumerations e "
+       "join fetch i.values "
+       "where i.id=cv.issue "
+       "and cv.customFields=cf.id "
+       "and e.id=i.priority "
+       "and (e.type=:priority and (e.position=:position1 or e.position=:position2)) "
+       "and (i.issueStatus.id=:status1 or i.issueStatus.id=:status2) "
+       "and cf.name = :date_denom "
+       "and str_to_date(cv.value, :date_format) > date(:date_ouverture)"
+       "and i.projects.name=:pole "
//+       "and :value member of i.values "
+       "group by i.id";

我的 REST 控制器:

@RestController
@RequestMapping("/issues")
public class IssuesRESTController extends GenericRestController<Issues> {

private List<Issues> listeM1;
private List<Issues> trashBin;

@Autowired
IssuesRepository issuesRepository;

@Autowired
DataM1Repository dataM1Repository;

@Autowired 
AuteurRepository auteurRepository;

@Autowired
PoleRepository poleRepository;

@Autowired
public IssuesRESTController(IssuesRepository repository, DataM1Repository dataM1Repository, AuteurRepository auteurRepository, PoleRepository poleRepository) {
    super(repository);
}

@PostConstruct
public void init() {
    Param.poles=new HashMap<>();
    int i=0;
    for(String s : issuesRepository.getPolesNames()) {
        Param.poles.put(i, s);
        i++;
    }
    listeM1= new ArrayList<>();
    trashBin = new ArrayList<>();
    listeM1 =  issuesRepository.getM1Issues();
    System.out.println(listeM1.size()+" Enregistrements récupérés dans la     variable listeM1");

    /**
     * On regarde si les tuples remontés sont déjà présent dans la base,
     * si oui, on les enlève de la liste à traiter.
     */

    System.out.println(listeM1.get(0).toString());

    for(Issues issue : listeM1) {
        for(DataM1 d : dataM1Repository.list()) {

            if(issue.getId()==d.getId_ticket()) {
                System.out.println("Ticket trouvé correspondant au tuple"+issue + "\n suppression du tuple de la liste à traiter");
                trashBin.add(issue);
                };
        }
    }

    for (Issues issue : trashBin) { // on évite java-util concurrentmodificationexception
        listeM1.remove(issue);
    }
    trashBin.clear();

    /**
     * On crée les tickets manquants, les poles et les auteurs suivant le besoin
     */
    for(Issues issue : listeM1) {

        System.out.println("Création dans la table outil des tickets manquants");

            DataM1 ticket = new DataM1();
            ticket.setId(Integer.SIZE);
            ticket.setId_ticket(issue.getId());

            System.out.println("*********\n Ticket : "+issue.getId()+"\n**********");
            System.out.println("Recherche l'auteur "+ issue.getAuthor().getLastname()+" "+issue.getAuthor().getFirstname()+" dans la base ...");
            System.out.println(issue.getValues());

            try {
                Auteur a = auteurRepository.findbyName(issue.getAuthor().getLastname(), issue.getAuthor().getFirstname());
                System.out.println("Auteur trouvé :"+a.getNom() + " "+a.getPrenom());
                ticket.setAuteur(a);

            }catch(NullPointerException e){
            System.out.println("Cet auteur n'est pas en base .. création ...");
            ticket.setAuteur(new Auteur(issue.getAuthor().getLastname(), issue.getAuthor().getFirstname()));
            }

            System.out.println("Recherche du pole "+issue.getProjects().getName()+" dans la base ...");

            try {
                Pole p = poleRepository.findbyName(issue.getProjects().getName());
                System.out.println("Pole trouvé : "+p.getNom_pole());
                ticket.setPole(p);
            }catch(NullPointerException e) {
                System.out.println("Ce pole n'est pas en base... création...");
                ticket.setPole(new Pole(issue.getProjects().getName()));
            }


            System.out.println("Création du ticket...");
            dataM1Repository.create(ticket);
            System.out.println("Ticket crée");


    }

}

@Override
@RequestMapping("/all")
public ResponseEntity<List<Issues>> list(){
    List<Issues> list = issuesRepository.getAll();
    return new ResponseEntity<List<Issues>> (list, HttpStatus.OK);
}

@RequestMapping("/M1/list")
public ResponseEntity<List<Issues>> listM1(){
    List<Issues> list = issuesRepository.getM1Issues();
    return new ResponseEntity<List<Issues>> (list, HttpStatus.OK);
}

@RequestMapping("/M1/count")
public ResponseEntity<Long> countM1(){
    Long nbIssues =   issuesRepository.countM1Issues();
    return new ResponseEntity<Long>(nbIssues, HttpStatus.OK);
}

@RequestMapping("/M1/poles") // recherche la liste des poles dans la base
public ResponseEntity<List<String>> getPolesNames(){
    List<String> poles = issuesRepository.getPolesNames();
    return new ResponseEntity<List<String>>(poles, HttpStatus.OK);
}

@RequestMapping("/M1/pole")
public ResponseEntity<List<Issues>> getPoleByName(@RequestParam(value="pole") int polekey){
    List<Issues> poles = issuesRepository.getPoleByName(polekey);



    return new ResponseEntity<List<Issues>>(poles, HttpStatus.OK);
}

@RequestMapping("/M1/pole/count")
public ResponseEntity<Long> countPoleByName(@RequestParam(value="pole") int polekey){
    Long poles = issuesRepository.CountPoleByName(polekey);
    return new ResponseEntity<Long>(poles, HttpStatus.OK);
}

@RequestMapping("/M1/pole/count/all")
public ResponseEntity<HashMap<String, Long>> getAllInformationOnPoles(){
    HashMap<String, Long> tabl = new HashMap<>();
    int i=0;
    for(String s :issuesRepository.getPolesNames()) {
        tabl.put(Param.poles.get(i), issuesRepository.CountPoleByName(i));
        i++;
    }

    return new ResponseEntity<HashMap<String, Long>>(tabl, HttpStatus.OK);
}

@RequestMapping("/M1/pole/count/red")
public ResponseEntity<HashMap<String, Long>> getAllRedInformationOnPoles(){
    HashMap<String, Long> tabl = new HashMap<>();
    int i=0;
    for(String s :issuesRepository.getPolesNames()) {
        tabl.put(Param.poles.get(i), issuesRepository.CountRedPoleByName(i));
        i++;
    }

    return new ResponseEntity<HashMap<String, Long>>(tabl, HttpStatus.OK);
}


@RequestMapping("/test/issue")
public ResponseEntity<Issues> listIssueFields(@RequestParam(value="issue") int id_issue){
    Issues list = issuesRepository.getIssueById(id_issue);
    return new ResponseEntity<Issues>(list, HttpStatus.OK);
}


}

我的实体类:

@Entity
@Table(name = "issues")
public class Issues {

public Issues() {}

/*
 * Primary key
 */
@Id
@Column(name = "id", unique = true, nullable = false)
private int id;

/*
 * Foreign keys
 */

@JoinColumn(name = "project_id")
@ManyToOne(targetEntity = Projects.class)
private Projects projects;

@JoinColumn(name = "status_id")
@ManyToOne(targetEntity = IssueStatuses.class)
private IssueStatuses issueStatus;

@JoinColumn(name = "author_id", referencedColumnName = "id")
@ManyToOne(targetEntity = Users.class)
private Users author;

@JoinColumn(name = "priority_id")
@ManyToOne(targetEntity = Enumerations.class)
private Enumerations priority;


/*
 * Fields
 */
@Column(name = "subject", nullable = false)
private String subject;

@Column(name = "description", nullable = true)
private String description;






@OneToMany(mappedBy = "issue", targetEntity = CustomValues.class, fetch = FetchType.LAZY)
private List<CustomValues> values;

@Transient
private Map<CustomFields, String> mapValeurs;

@Transient
private IssueStatuses status;

//getters & setters

我的仓库:

@Repository
public class IssuesRepository extends GenericCRUDImplRedmine<Issues>{

public IssuesRepository() {
    super();
    System.out.println(Repositories.BUILD+this.getClass().getSimpleName());
}

@SuppressWarnings("unchecked")
public List<Issues> getAll() {
    String sql = Database.GET_ALL_ISSUES;
    return super.getCurrentSession().createQuery(sql).getResultList();
}


@SuppressWarnings("unchecked")
public List<Issues> getM1Issues(){
    String sql = Database.GET_RECORDS_FOR_M1;
    System.out.println("requete : "+sql);
    List<Issues> M1Issues =(List<Issues>)  super.getCurrentSession().createQuery(sql)
                            .setParameter("priority", Param.priority)
                            .setParameter("position1", Param.position[0])
                            .setParameter("position2", Param.position[1])
                            .setParameter("status1", Param.status[0])
                            .setParameter("status2", Param.status[1])
                            .setParameter("date_ouverture", Date.date_ouverture)
                            .setParameter("date_resolution", Date.date_resolution)
                            .setParameter("date_format", Date.FORMAT_DATE_M1)
                            .setParameter("date_denom", Date.date_denom)
                            .setParameter("pole", Param.poles.get(0)) // define the key
                            //.setParameter("value", 1)
                            .getResultList();

    return  M1Issues;
}

我的通用 CRUD 实现:

@Transactional("hibernateTransactionManagerRedmine")

公共类 GenericCRUDImplRedmine 实现 GenericCRUD {

private final Class<T> persistentClass;

@Autowired
@Qualifier("sessionFactoryRedmine")
private SessionFactory sessionFactory;




protected Session getCurrentSession() {
    boolean testSessionFactory = sessionFactory!=null;
    System.out.println("Avons nous une sessionFactory?  "+testSessionFactory);

    Session session = sessionFactory.getCurrentSession();
    boolean testSession = session!=null;
    System.out.println("Avons nous une session?  "+testSession);
    return session;
}   

@SuppressWarnings("unchecked")
public GenericCRUDImplRedmine() {
    this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
            .getActualTypeArguments()[0];
}

@Override
public void create(final T entity) {
    this.getCurrentSession().save(entity);
}

@Override
public void update(T t) {
    this.getCurrentSession().update(t);

}

@Override
public void refresh(T t) {
    // TODO Auto-generated method stub

}

@Override
public void delete(Integer id) {
    this.getCurrentSession().delete(this.find(id));

}

@Override
public T find(Integer id) {
    // TODO Auto-generated method stub
    return (T) this.getCurrentSession().get(persistentClass, id);
}

@SuppressWarnings("unchecked")
@Override
public List<T> list() {
    // TODO Auto-generated method stub
    return this.getCurrentSession().createQuery("from "+persistentClass).getResultList();
}

数据库配置:

@Configuration
@EnableTransactionManagement
public class DBConfig {

/**
 * Créer la fabrique de session à la base de données et associe les entités
 * utilisables dans la session.
 * 
 * @return SessionFactory
 */
@Bean(name="sessionFactoryOutil")
public SessionFactory sessionFactoryOutil() {
    System.out.println("Construction de l'objet SessionFactory pour l'outil...");
    return new LocalSessionFactoryBuilder(getDataSourceOutil())
            .scanPackages("fr.alteca.outilindicateurs.entityOutil")
            .buildSessionFactory();
}

@Bean(name="sessionFactoryRedmine")
public SessionFactory sessionFactoryRedmine() {
    System.out.println("Construction de l'objet SessionFactory pour Redmine...");
    return new LocalSessionFactoryBuilder(getDataSourceRedmine())
            .scanPackages("fr.alteca.outilindicateurs.entityRedmine")
            .buildSessionFactory();
}

/**
 * Configure l'accès à la base de données.
 * La configuration à la base de données se trouve dans le fichier de contexte (WebContent / META-INF / context.xml)
 * 
 * @return DataSource
 */
@Bean(name="dataSourceOutil")
public DataSource getDataSourceOutil() {

    try {
        InitialContext initialContext = new InitialContext();
        DataSource datasource = (DataSource) initialContext.lookup( "java:/comp/env/jdbc/postgres" );
        System.out.println("Base de donnée outil Localisée");
        return datasource;

    } catch (NamingException e) {
        e.printStackTrace();
        return null;
    }

}

@Bean(name="dataSourceRedmine")
public DataSource getDataSourceRedmine() {

    try {
        InitialContext initialContext = new InitialContext();
        DataSource datasource = (DataSource) initialContext.lookup( "java:/comp/env/jdbc/redmine" );
        System.out.println("Base de donnée Redmine Localisée");
        return datasource;

    } catch (NamingException e) {
        e.printStackTrace();
        return null;
    }

}

/**
 * Défini Hibernate pour la transaction à la base de données.
 * 
 * @return
 */
@Bean(name="hibernateTransactionManagerOutil")
public HibernateTransactionManager hibernateTransactionManagerOutil() {
    System.out.println("initialisation du transaction manager pour l'outil !");
    return new HibernateTransactionManager(this.sessionFactoryOutil());
}

@Bean(name="hibernateTransactionManagerRedmine")
public HibernateTransactionManager hibernateTransactionManagerRedmine() {
    System.out.println("initialisation du transaction manager pour Redmine !");
    return new HibernateTransactionManager(this.sessionFactoryRedmine());
}

【问题讨论】:

  • 所以某些东西(查询?)正在返回 Object[],而您将其视为其他东西。还有?
  • 忘记提及我的存储库,更新了我的帖子。在那里进行类转换,因为问题扩展了对象,为什么我应该有一个类转换异常?我认为它来自映射。我相信 java 的行为是这样的,因为他无法构建与传入数据对象相对应的问题对象。
  • JPA(如果您正在使用它,它没有“会话”)不接受“SQL”到createQuery。它采用 JPQL。如果您发布的查询(带有结果子句)是您正在调用的,那么它显然会返回 Object[],根据 JPA 规范
  • 我的数据库实现是正确的,我可以发布它供您审查。我正在使用休眠。
  • 您的数据库实现与什么有什么关系?错误不存在。您正在执行一个查询“SELECT i, MAX(...) FROM ...”,它返回多个对象,因此 getResultList 的返回是Object[],因此将其转换为其他东西是一件奇怪的事情。如果您只是在执行“SELECT i FROM ...”,那会很好...您不是,所以不是。基础 Java。

标签: hibernate class jpa exception casting


【解决方案1】:

好的,我明白了,我无法在同一个查询中返回多个对象,实际上这不是您所说的 JPA 问题。我设法通过它将查询分为 3 个查询(我认为这是肮脏的方式),它有效,但我仍然会寻找一种更清洁的方式来这样做

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 2010-12-06
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多