Search code examples
javaglassfishcdimybatisweld

MyBatis CDI beanManager.getBeans fails to find SqlSessionFactory bean in GlassFish 4 and 4.1


I have created a simple Java EE program to experiment with MyBatis but I've hit a problem using the MyBatis CDI module. I have followed the instructions outlined on http://mybatis.github.io/cdi/injection.html, but when my program tries to use MyBatis a MybatisCdiConfigurationException exception is thrown with the description "There are no SqlSessionFactory producers properly configured."

The code for the SqlSessionFactory I'm using is as follow:

import javax.annotation.Resource;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.sql.DataSource;

import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

public class SqlSessionFactoryProvider {

    @Resource (name="jdbc/MyDatabase")
    DataSource dataSource;

    @Produces
    @ApplicationScoped
    public SqlSessionFactory produceFactory() {
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        Environment environment = new Environment("development",
                transactionFactory, dataSource);
        Configuration configuration = new Configuration(environment);
        configuration.addMapper(ToDoItemMapper.class);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
                .build(configuration);
        return sqlSessionFactory;
    }
}

I've stepped through the code of the MyBatis CDI module and have found that when the follow line of code in CDIUtils findSqlSessionFactory(...) is executed it fails find any beans that return SqlSessionFactory.class.

beans = beanManager.getBeans(SqlSessionFactory.class, qualifiers.toArray(new Annotation[]{}));

I've tried running my program on GlassFish 4 and 4.1 and they both have the same problem, but it works find if I run my program on WildFly 8.1. My first thought was that it might be a problem with the version of Weld shipped with Glassfish but it turns out that GlassFish 4.1 is running Weld version 2.2.2 whereas WildFly is running Weld version 2.1.2.

Is there anything I can do in GlassFish, my code or in the MyBatis CDI module to overcome this problem when running in GlassFish? Alternatively can anyone suggest anything that I can do to investigate the problem further please?


Solution

  • I ran into the same issue when trying to implement the mybatis-CDI running in Jboss wildfly. I found the solution when going through this git smaple project: https://github.com/artplastika/mybatis-cdi-example

    The only thing you seem to be missing is the @Local, @Stateless and @Named annotations on your SqlSessionFactoryProvider.java class

    See the SqlSessionFactoryProvider.java class in the Git example: https://github.com/artplastika/mybatis-cdi-example/blob/master/mybatis-cdi-example-ejb/src/main/java/org/mybatis/cdi/example/beans/SqlSessionFactoryProviderImpl.java

    You should also ensure that you have the beans.xml in you src/main/resources/META-INF folder

    EDIT

    My Maven Dependency Setup:

    <dependencies>
            <dependency>
                <groupId>javax</groupId>
                <artifactId>javaee-api</artifactId>
                <version>7.0</version>
                <scope>compile</scope>
            </dependency>
            <!-- Import the CDI API -->
            <dependency>
                <groupId>javax.enterprise</groupId>
                <artifactId>cdi-api</artifactId>
                <version>1.2</version>
                <scope>compile</scope>
            </dependency>
            <!-- Mybatis Dependencies -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.2.5</version>
                <scope>compile</scope>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-cdi</artifactId>
                <version>1.0.0-beta1</version>
                <scope>compile</scope>
            </dependency>
            <!-- Below Dependencies are very specific to Jboss due to class conflicts if you dont have the exclusions specified -->
            <!-- Proxy support (Mandatory) -->
            <dependency>
                <groupId>cglib</groupId>
                <artifactId>cglib</artifactId>
                <scope>compile</scope>
                <version>2.2.2</version>
                <exclusions>
                    <exclusion>
                        <groupId>asm</groupId>
                        <artifactId>asm</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!-- Internal dependency (Required) -->
            <dependency>
                <groupId>org.ow2.asm</groupId>
                <artifactId>asm-util</artifactId>
                <version>5.0.3</version>
                <scope>compile</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.ow2.asm</groupId>
                        <artifactId>asm</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!-- Internal dependency (Required) -->
            <dependency>
                <groupId>opensymphony</groupId>
                <artifactId>oscache</artifactId>
                <version>2.4</version>
                <scope>compile</scope>
                <!-- This excludes the transitive dependency on JMS -->
                <exclusions>
                    <exclusion>
                        <groupId>javax.jms</groupId>
                        <artifactId>jms</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    

    I've got my sample Factory Producer as below:

    @Stateless
    @Local(SampleSqlSessionFactoryProvider.class)
    public class SampleSqlSessionFactoryProvider {
        @Produces
        @ApplicationScoped
        @Named("sqlSessionFactory")
        public SqlSessionFactory produceFactory() throws Exception {        
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            SqlSessionFactory sqlSessionFactory = null;
            String environment = "default";
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader, environment);
            return sqlSessionFactory;
        }
    }
    

    and to use it i inject it as follows:

    @Local(DaoBean.class)
    @Stateless
    public class DoaBean{
         private @Inject @Named("sqlSessionFactory") SqlSession session;
         public void doStuff(){
             session.selectOne(...);
         }
         ...
    }