ClassCastException DTO OSGI

时间:2015-10-27 01:21:57

标签: osgi apache-karaf blueprint-osgi

我有三个蓝图束(不同的罐子):

  • ap-data :只包含一个名为Game.java的类,应该用作DTO。它是一个实体,用@Entity注释。
  • ap-dao :一个持久性包,其中包含OSGI清单中的persistence.xml,Meta-Persistence标头,并从 ap-data 导入Game.java。
  • ap-service :还会从 ap-data 导入Game.java,以及由 ap-dao ,IGameDAO.java公开的界面。它也公开了IGameService.java。

意识到这些捆绑包形成了模块游戏的层次。情形:

  • 所有捆绑包都在Karaf 3.0.5中正确部署(都是“活动”)。
  • ap-dao bundle正确加载为持久性捆绑包,可以访问已配置的数据源并可以正常访问EntityManager。它可以执行查询,我可以看到结果。一切都很好。
  • ap-service 可以毫无问题地注入IGameDAO实例。一切都很好,直到这里。
  • 类Game.java(DTO)仅包含在ap-data包中。没有重复(我检查过)。

问题:

GameServiceImpl中的游戏 类型 ap-service 捆绑类加载器加载,而IGameDAO服务返回的实例属于另一种类型因为它们是由 ap-dao 包类加载器加载的,因此会生成ClassCastException。意识到这个类是相同的(app.Game.java),应该是DTO。 DTO是我必须能够使用的基本对象,并通过bundle(通过服务)传递它们。如何在OSGI中处理DTO?我该如何解决这个问题?

// code in GameServiceImpl, from ap-service bundle
public void prettyPrintGames() {
    List<Game> games = gameDao().findAll();

    /* ClassCastException in the for-loop, since the type Game, in ap-service
     * is not the same of the instances of varible 'games', 
     * returned by the DAO service instance. This is the reason
     * of the classloader issue.
     */
    for(Game g : games){
        System.out.println(g.toString()); 
    }
}

结构:

AP-数据

+---ap-data
|   |   pom.xml
|   |       
|   +---src
|   |   \---main
|   |       +---java
|   |       |   \---br
|   |       |       \---com
|   |       |           \---company
|   |       |               \---game
|   |       |                   \---entity
|   |       |                           Game.java

捆绑清单:

Manifest-Version: 1.0
Bnd-LastModified: 1445945039034
Build-Jdk: 1.7.0_07
Built-By: user
Bundle-Description: ap-data
Bundle-ManifestVersion: 2
Bundle-Name: ap-data
Bundle-SymbolicName: ap-data
Bundle-Version: 1.0.0
Created-By: Apache Maven Bundle Plugin
Export-Package: br.com.company.game.entity;version="1.0.0";uses:="javax.
 persistence"
Import-Package: javax.persistence;version="[2.1,3)"
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))"
Tool: Bnd-3.0.0.201509101326

AP-DAO

+---ap-dao
|   |   pom.xml
|   +---src
|   |   \---main
|   |       +---java
|   |       |   \---br
|   |       |       \---com
|   |       |           \---company
|   |       |               \---game
|   |       |                   \---dao
|   |       |                       +---api
|   |       |                       |       IGameDAO.java
|   |       |                       |       
|   |       |                       \---impl
|   |       |                               GameDAOImpl.java
|   |       |                               
|   |       \---resources
|   |           +---META-INF
|   |           |       persistence.xml
|   |           |       
|   |           \---OSGI-INF
|   |               \---blueprint
|   |                       blueprint.xml
|   |                       

Bundle Manifest

Manifest-Version: 1.0
Bnd-LastModified: 1445945039855
Build-Jdk: 1.7.0_07
Built-By: user
Bundle-Blueprint: OSGI-INF/blueprint/blueprint.xml
Bundle-Description: game-module
Bundle-ManifestVersion: 2
Bundle-Name: ap-dao
Bundle-SymbolicName: ap-dao
Bundle-Version: 1.0.0
Created-By: Apache Maven Bundle Plugin
Export-Package: br.com.company.game.dao.api;version="1.0.0";uses:="br.co
 m.company.game.entity"
Export-Service: br.com.company.game.dao.api.IGameDAO
Import-Package: br.com.company.game.dao.api;version="[1.0,2)",br.com.com
 pany.game.entity;version="[1.0,2)",javax.persistence;version="[2.1,3)",
 org.osgi.service.blueprint;version="[1.0.0,2.0.0)"
Meta-Persistence: META-INF/persistence.xml
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))"
Tool: Bnd-3.0.0.201509101326

AP-服务

+---ap-service
|   |   pom.xml
|   |   
|   +---src
|   |   \---main
|   |       +---java
|   |       |   \---br
|   |       |       \---com
|   |       |           \---company
|   |       |               \---game
|   |       |                   \---service
|   |       |                       +---api
|   |       |                       |       IGameService.java
|   |       |                       |       
|   |       |                       \---impl
|   |       |                               GameServiceImpl.java
|   |       |                               
|   |       \---resources
|   |           \---OSGI-INF
|   |               \---blueprint
|   |                       service.xml
|   |                       

捆绑清单

Manifest-Version: 1.0
Bnd-LastModified: 1445945040469
Build-Jdk: 1.7.0_07
Built-By: user
Bundle-Blueprint: OSGI-INF/blueprint/service.xml
Bundle-Description: game-module
Bundle-ManifestVersion: 2
Bundle-Name: ap-service
Bundle-SymbolicName: ap-service
Bundle-Version: 1.0.0
Created-By: Apache Maven Bundle Plugin
Export-Package: br.com.company.game.service.api;version="1.0.0"
Export-Service: br.com.company.game.service.api.IGameService
Import-Package: br.com.company.game.dao.api;version="[1.0,2)",br.com.com
 pany.game.entity;version="[1.0,2)",br.com.company.game.service.api;vers
 ion="[1.0,2)",org.osgi.service.blueprint;version="[1.0.0,2.0.0)"
Import-Service: br.com.company.game.dao.api.IGameDAO;multiple:=false
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.7))"
Tool: Bnd-3.0.0.201509101326

分析:

我在ap-dao中做了一些测试,并且意识到如果我返回实体而不通过EntityManager,例如,创建硬编码的对象,一切正常。一旦我使用entityManager查询实体,问题就会再次出现,我得到ClassCastException。

private EntityManager entityManager;

    @SuppressWarnings("unchecked")
    @Override
    public List<Game> findAll() {
        return _findAllHardCoded(); // this work just fine in service layer, no ClassCastException

        return entityManager.createQuery("SELECT s FROM Game s").getResultList(); // if I use this, ClassCastException is generated in the service layer

    }

    protected List<Game> _findAllHardCoded() {
        List<Game> games = new ArrayList<Game>();
        games.add(new Game(Short.valueOf("1"), "Game1"));
        games.add(new Game(Short.valueOf("2"), "Game2"));
        return games;
    }

2 个答案:

答案 0 :(得分:1)

如果你的设置是正确的,那么ap-data应该包含Game类,并且包含Game包的Export-Package。另外两个bundle应该有一个这个包的Import-Package语句。在这种情况下,类Game只能由ap-data的类加载器加载。

还要注意如何设置maven bundle插件。例如,如果您告诉它导出包含在另一个包中的包,那么它会将其嵌入您自己的包中。所以最简单的方法就是将其保留为默认值。

你可以寻找的东西是。多个包中不应包含任何包。您应该使用Aries JPA来进行JPA访问。正如Balazs评论说,持久性提供者经常在内部做黑魔法。与Aries JPA结合使用它应该在OSGi中工作,但如果你使用普通的JPA,可能会有问题。

我在github上检查了这个项目。我认为问题是persistence.xml的位置。此文件应始终位于包含实体类的项目中。你能尝试移动吗?

答案 1 :(得分:0)

相应于Christian Schneider,如评论中所示,尝试在运行时更新KAR文件,在任何持久性束中使用EntityManager,在尝试转换实体类型的bundle之间生成ClassCastException,Aries JPA 1.x的已知问题是什么。 Aries JPA 2x是要走的路。谢谢!