我有一个非常有趣的问题,在过去的两天里一直让我抓狂。
我正在使用jUnit和嵌入式Tomcat来测试一些API端点(Jersey)。 我不太喜欢模拟,我进行此设置是为了在尽可能接近生产的条件下测试 API 响应。
当 API 收到调用时,它应该提供相应的响应(找到、未找到等)。这就是 Hibernate 发挥作用的地方。
当我在 Eclipse 中设置的 Tomcat 上运行此命令时,或者当我在远程服务器上的独立 Tomcat 上部署构建(Maven)时,一切正常,但在测试期间在嵌入式 Tomcat 上调用 API 时我收到此错误:
java.lang.ClassCastException: com.models.listing.Listing cannot be cast to 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 embedded 8.5.3
Hibernate 5.2.1
我最好的选择是类加载器存在一些问题。 我知道,如果类是用不同的类加载器加载的,那么 JVM 会将类视为不同的类,即使它基本上是来自同一个包的相同类等等,但我似乎找不到一种方法来实现这一点。
也许我的假设完全错误,我在这里遗漏了一些东西,所以如果有人遇到过类似的事情或有一些建议(我已经尝试了数十个“解决方案”)请加入。
提前感谢大家的帮助!
最佳答案
我仍然没有弄清楚其中的奥秘,在使用类加载器等进行了一些其他“反复试验”的想法之后,我就放弃了。
我通过降级到 hibernate 4.3.11 来“修复”它
关于java - jUnit、嵌入式 Tomcat 和 Hibernate java.lang.ClassCastException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38420356/