使用Spring Data JPA和Spring Data Cassandra时,使用Spring Boot 1.3.1的VerifierMappingExceptions

时间:2016-03-08 16:23:24

标签: spring-boot spring-data-cassandra

我正在使用Spring-boot-starter-parent让Spring管理我项目的所有依赖项,并且我正在使用Spring Data Cassandra和Spring数据JPA

Spring-boot-starter-parent的版本是1.2.8.RELEASE.Lately我将版本更新为1.3.1.RELEASE并开始面临Spring Data Cassandra的一个奇怪问题

mvn:eclipse:eclipse

它说我必须使用@Table等注释实体,但这些实体是Spring数据JPA Spring数据Cassandra的实体我已用@Table等注释

Start-class:

 21:23:21.783 [localhost-startStop-1] WARN  org.apache.catalina.loader.WebappClassLoaderBase   - Failed to check for ThreadLocal references for web application [ROOT]
java.lang.UnsupportedOperationException: null
    at com.zaxxer.hikari.util.FastList.iterator(FastList.java:209) ~[HikariCP-2.4.3.jar:na]
    at org.apache.catalina.loader.WebappClassLoaderBase.loadedByThisOrChild(WebappClassLoaderBase.java:2195) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks(WebappClassLoaderBase.java:2105) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalsForLeaks(WebappClassLoaderBase.java:2060) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappClassLoaderBase.clearReferences(WebappClassLoaderBase.java:1575) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappClassLoaderBase.stop(WebappClassLoaderBase.java:1521) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.loader.WebappLoader.stopInternal(WebappLoader.java:447) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5517) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.util.LifecycleBase.stop(LifecycleBase.java:232) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1424) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at org.apache.catalina.core.ContainerBase$StopChild.call(ContainerBase.java:1413) [tomcat-embed-core-8.0.30.jar:8.0.30]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_72]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_72]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_72]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_72]
21:23:21.791 [main] ERROR org.springframework.boot.SpringApplication         - Application startup failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.service.intf.UserService com.sarvint.rest.UserController.uService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.repositories.UserRepository com.sarvint.service.UserServiceImpl.userRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is org.springframework.data.cassandra.mapping.VerifierMappingExceptions: com.sarvint.domain.User:
Cassandra entities must have the @Table, @Persistent or @PrimaryKeyClass Annotation

    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538) ~[spring-context-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) ~[spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:764) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:357) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:305) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1124) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1113) [spring-boot-1.3.1.RELEASE.jar:1.3.1.RELEASE]
    at com.sarvint.Application.main(Application.java:18) [classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.service.intf.UserService com.sarvint.rest.UserController.uService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.repositories.UserRepository com.sarvint.service.UserServiceImpl.userRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is org.springframework.data.cassandra.mapping.VerifierMappingExceptions: com.sarvint.domain.User:
Cassandra entities must have the @Table, @Persistent or @PrimaryKeyClass Annotation

    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    ... 17 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.sarvint.repositories.UserRepository com.sarvint.service.UserServiceImpl.userRepo; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Invocation of init method failed; nested exception is org.springframework.data.cassandra.mapping.VerifierMappingExceptions: com.sarvint.domain.User:
Cassandra entities must have the @Table, @Persistent or @PrimaryKeyClass Annotation

}

Spring Data JPA配置:

@SpringBootApplication
@EnableJpaRepositories( repositoryFactoryBeanClass =    GenericRepositoryFactoryBean.class )
@EntityScan("com.sarvint.domain")
@Import(CassandraConfig.class)
public class Application {

public static void main( String[] args ) throws Exception
{
    SpringApplication.run(Application.class, args);
}

Spring Data JPA实体:

@Configuration
@ComponentScan( basePackages = "com.sarvint" )
@PropertySource( value = { "classpath:application.properties" } )
public class AppConfig extends WebMvcConfigurerAdapter {

@Autowired
private Environment environment;

                                                                                                                                                                                                                                            @Override
public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer )
{
    configurer.enable();
}

@Bean
public DataSource dataSource()
{
    HikariConfig config = new HikariConfig();
    int poolSize = 20;
    config.setMaximumPoolSize(poolSize);
    config.setDataSourceClassName(environment.getRequiredProperty("spring.datasource.driver-class-name"));
    config.addDataSourceProperty("url", environment.getRequiredProperty("spring.datasource.url"));
    config.addDataSourceProperty("user", environment.getRequiredProperty("spring.datasource.username"));
    config.addDataSourceProperty("password", environment.getRequiredProperty("spring.datasource.password"));
    return new HikariDataSource(config);
}

现在来到Spring Data Cassandra配置:

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

@Entity
@Table( name = "user" )

public class User implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue( strategy = GenerationType.IDENTITY )
@Column( name = "u_id" )
private Integer userId;

@Column( name = "u_first_name" )
private String firstName;

@Column( name = "u_last_name" )
private String lastName;
}

Spring Cassandra实体:

    package com.sarvint.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.cassandra.config.CassandraClusterFactoryBean;
import org.springframework.data.cassandra.config.java.AbstractCassandraConfiguration;
import org.springframework.data.cassandra.mapping.BasicCassandraMappingContext;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories;

@Configuration
@PropertySource(value = { "classpath:cassandra.properties" })
@EnableCassandraRepositories(basePackages="com.sarvint.cassandra.domain")
public class CassandraConfig extends AbstractCassandraConfiguration {

    private static final Logger LOG = LoggerFactory.getLogger(CassandraConfig.class);


    @Autowired
    private Environment environment;

    @Bean
    public CassandraClusterFactoryBean cluster() {
        LOG.info("INSIDE cluster()");
        CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
        cluster.setContactPoints(environment.getProperty("cassandra.contactpoints"));
        cluster.setPort(Integer.parseInt(environment.getProperty("cassandra.port")));
        return cluster;
    }

    @Override
    protected String getKeyspaceName() {
        LOG.info("INSIDE getting keyspace name");
        return environment.getProperty("cassandra.keyspace");
    }

    @Bean
    public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
        LOG.info("INSIDE cassandra mapping");
        return new BasicCassandraMappingContext();
    }
}

Cassandra.properties

import org.springframework.cassandra.core.PrimaryKeyType;
import org.springframework.data.cassandra.mapping.Column;
import org.springframework.data.cassandra.mapping.PrimaryKeyColumn;
import org.springframework.data.cassandra.mapping.Table;

@Table( value = "biometric_param" )
public class BiometricParam {

    @PrimaryKeyColumn(name="user_id",ordinal=0,type=PrimaryKeyType.PARTITIONED)
    private Integer userId;

    @PrimaryKeyColumn(name="workout_uuid",ordinal=1,type=PrimaryKeyType.PARTITIONED)
    private String workoutUUID;

    @PrimaryKeyColumn(name="bio_param_key",ordinal=2,type=PrimaryKeyType.CLUSTERED)
    private String bioParamKey;

    @Column(value="bio_param_val")
    private Float bioParamValue;
}

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

问题是什么?

这是Spring Data Cassandra中的一个错误。您的类路径上有多个Spring Data模块。在这种情况下,Spring Data会尝试确定特定存储库所属的模块。 Spring Data Cassandra错过了一点来识别您的JPA实体User不属于Cassandra,因此Spring Data Cassandra尝试为您的UserRepository创建一个Repository实例。

如果启用DEBUG日志记录,您将看到一些DEBUG日志消息,指出Spring Data正在进入严格配置模式。

为什么现在出现这个bug而不是早期的Spring Boot版本?

Spring Boot 1.3.0引入了Spring Data Cassandra存储库的自动配置。由于此更改,Spring Boot执行scan for Spring Data Cassandra repositories,就像您仅使用@EnableCassandraRepositories配置它一样。

只有使用多个Spring Data模块的默认EnableCassandraRepositories组合才会发现此错误。

那么,现在呢?

spring.data.cassandra.repositories.enabled=false设置application.properties以禁用自动配置,因为您自己使用@EnableCassandraRepositories(basePackages="com.sarvint.cassandra.domain")

我创建了一个错误报告here,因此您可以根据需要跟踪进度。

答案 1 :(得分:1)

尝试升级到HikariCP 2.4.4。它包含此修复:

issue 495: implemented iterator() method on custom FastList to support Tomcat memory leak detection.