0

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?

Paul H
  • 2,104
  • 7
  • 39
  • 53

2 Answers2

0

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(...);
     }
     ...
}
  • I've just tried adding the `@Local`, `@Stateless` and `@Named` annotations but I'm still getting `MybatisCdiConfigurationException`. What version of GlassFish and Weld are you using? – Paul H Apr 09 '15 at 00:02
  • I am using JBoss Wildfly (8.2). If you are still getting that error then it is possibly related to the way you're trying to Inject the `org.apache.ibatis.session.SqlSession`. Alternatively it could be some permutation of a class path issue. Is your project maven? – Ryan Zakariudakis Apr 09 '15 at 11:18
  • What seems odd is that I can do `@Inject private SqlSession sqlSession;` and the SqlSession bean is injected fine and I run queries using MyBatis. The problem only presents itself by I try to inject a `Mapper` bean. For example doing `@Inject @Mapper private ToDoItemMapper toDoItemMapper;` causes the `MybatisCdiConfigurationException` exception to be thrown because `CDIUtils.findSqlSessionFactory(...)` can't find a factory method which returns `SqlSessionFactory ` – Paul H Apr 09 '15 at 12:02
0

I have found a workaround to this problem but not really the solution I was hoping for. I've copied the various classes that make up mybatis-cdi directly into my program and have registered the extension in META-INF/services/javax.enterprise.inject.spi.Extension, and I can now successfully inject mappers into my program and run queries using MyBatis.

I've raise this as an issue in the MyBatis-CDI GitHub repository and will update this answer if there is a fix.

Paul H
  • 2,104
  • 7
  • 39
  • 53