jUnit,嵌入式Tomcat和Hibernate java.lang.ClassCastException

时间:2016-07-17 10:41:44

标签: java hibernate tomcat junit jersey

我有这个非常有趣的问题让我在过去的两天里把头发拆掉了。

我正在使用 jUnit 嵌入式Tomcat 来测试一些API端点( Jersey )。 我不是嘲笑的忠实粉丝,我做了这个设置来测试API响应,条件尽可能接近生产。

当API收到呼叫时,它应该相应地提供响应(找到,找不到等)。这就是 Hibernate 的用武之地。

当我在eclipse中设置的Tomcat上运行它时,或者当我在远程服务器上的独立Tomcat上部署构建(Maven)时,一切正常,但是在测试期间在嵌入式Tomcat上调用API时我收到这个错误:

  

java.lang.ClassCastException:com.models.listing.Listing不能   强制转换为com.models.listing.Listing

是的,它是同一个类名。

要检索Listing对象,我使用Hibernate标准来获取ID

的持久化对象
Listing listing = session.get(Listing.class, ID);

这是嵌入式tomcat设置的样子:

public void start(String appName) throws Exception {
    File root = getRootFolder();
    System.setProperty("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE", "true");
    Path tempPath = Files.createTempDirectory("tomcat-base-dir");

    tomcat = new Tomcat();
    tomcat.setPort(0);
    tomcat.enableNaming();
    tomcat.setSilent(true);
    tomcat.setBaseDir(tempPath.toString());

    tomcat.getHost().setDeployOnStartup(true);
    tomcat.getHost().setAutoDeploy(true);
    tomcat.getHost().setAppBase(tempPath.toString());

    File webContentFolder = new File(root.getAbsolutePath(), "src/main/webapp/");
    if (!webContentFolder.exists()) {
        webContentFolder = Files.createTempDirectory("default-doc-base").toFile();
    }

    StandardContext ctx = (StandardContext) tomcat.addWebapp("/" + appName, webContentFolder.getAbsolutePath());

    //Disable TLD scanning by default
    if (System.getProperty(Constants.SKIP_JARS_PROPERTY) == null ) {
        System.out.println("disabling TLD scanning");
        StandardJarScanFilter jarScanFilter = (StandardJarScanFilter) ctx.getJarScanner().getJarScanFilter();
        jarScanFilter.setTldSkip("*");
    }

    System.out.println("configuring app with basedir: " + webContentFolder.getAbsolutePath());

    // Declare an alternative location for your "WEB-INF/classes" dir
    // Servlet 3.0 annotation will work
    File additionWebInfClassesFolder = new File(root.getAbsolutePath(), "target/classes");
    WebResourceRoot resources = new StandardRoot(ctx);

    WebResourceSet resourceSet;
    if (additionWebInfClassesFolder.exists()) {
        resourceSet = new DirResourceSet(resources, "/WEB-INF/classes", additionWebInfClassesFolder.getAbsolutePath(), "/");
        System.out.println("loading WEB-INF resources from as '" + additionWebInfClassesFolder.getAbsolutePath() + "'");
    } else {
        resourceSet = new EmptyResourceSet(resources);
    }
    resources.addPreResources(resourceSet);
    ctx.setResources(resources);

    //start tomcat
    tomcat.start();
}

这就是Hibernate配置的样子:

private static SessionFactory buildSessionFactory() {
    // setup the session factory
    Configuration configuration = new Configuration();

    //add annotated classes
    configuration.addAnnotatedClass(Listing.class);

    //connection properties
    configuration.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
    configuration.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
    configuration.setProperty("hibernate.connection.url", "jdbc:mysql://<some IP>:3306/<some db name>");
    configuration.setProperty("hibernate.connection.release_mode", "auto");
    configuration.setProperty("hibernate.connection.username", "<some username>");
    configuration.setProperty("hibernate.connection.password", "<some password>");
    configuration.setProperty("hibernate.connection.provider_class", "org.hibernate.connection.C3P0ConnectionProvider");

    //sql properties
    configuration.setProperty("show_sql", "true");
    configuration.setProperty("format_sql", "true");

    //misc properties
    configuration.setProperty("hibernate.hbm2ddl.auto", "validate");
    configuration.setProperty("hibernate.current_session_context_class", "thread");

    //c3p0 properties
    configuration.setProperty("hibernate.c3p0.min_size", "1");
    configuration.setProperty("hibernate.c3p0.max_size", "10");
    configuration.setProperty("hibernate.c3p0.timeout", "100");
    configuration.setProperty("hibernate.c3p0.max_statements", "50");
    configuration.setProperty("hibernate.c3p0.idle_test_period", "1000");
    configuration.setProperty("hibernate.c3p0.validate", "true");

    //return null
    return configuration.buildSessionFactory();
}

总而言之,测试在jUnit中启动,嵌入式tomcat实例启动,并且使用REST客户端向API端点发送请求。端点在从Hibernate检索资源后响应。

依赖版本:

  

Glassfish Jersey 2.23

     

jUnit 4.11

     

Tomcat嵌入式8.5.3

     

Hibernate 5.2.1

我最好的选择是类加载器的一些问题。 我知道JVM看到类不同,如果它们加载了不同的类加载器,即使它基本上是同一个包中的同一个类,依此类推,但我似乎没有办法让这个工作。

也许我的假设是完全关闭的,我在这里遗漏了一些东西,所以如果有人遇到过这样的事情或有一些建议(我已经尝试了几十个“解决方案”),请跳进去。

提前感谢大家的帮助!

1 个答案:

答案 0 :(得分:2)

我仍然没有弄清楚这个谜团,我只是放弃了一些其他的“试错法”与类加载器的想法等等。

我通过降级到休眠4.3.11来“修复”它。