I am planning to remove JPA (Eclipselink) from my project and use MyBatis instead of it. I was searching for some nice guide what is the best practice to use MyBatis in a EE container (statelass session ejb) and JNDI datasource + DAO pattern + CDI (I am not using Spring!). Unfortunately I have not found any good documentation about it.
Is there any way to initialize MyBatis and use JNDI data source without xml configuration file?
What is the best MyBatis way to implement DAO pattern and inject my dao classes to stateless EJB with CDI?
I use Java 8 + Glassfish (Payara EE server) + MyBatis 3.4.2.
UPDATE-1
I followed the instruction on this page http://www.mybatis.org/cdi/getting-started.html but it does not work for me.
This is the runtime exception what I got with Glassfish (actually it is a Payara) application server:
[2017-02-14T22:02:23.715+0100] [Payara 4.1] [INFO] [AS-WEB-GLUE-00172] [javax.enterprise.web] [tid: _ThreadID=101 _ThreadName=admin-listener(6)] [timeMillis: 1487106143715] [levelValue: 800] [[
Loading application [mybatis-demo-1.0#mybatis-demo-war-1.0.war] at [/demo]]]
[2017-02-14T22:02:23.770+0100] [Payara 4.1] [INFO] [] [javax.enterprise.system.core] [tid: _ThreadID=101 _ThreadName=admin-listener(6)] [timeMillis: 1487106143770] [levelValue: 800] [[
mybatis-demo-1.0 was successfully deployed in 1,526 milliseconds.]]
[2017-02-14T22:03:00.333+0100] [Payara 4.1] [INFO] [] [javax.enterprise.web] [tid: _ThreadID=25 _ThreadName=http-listener-1(2)] [timeMillis: 1487106180333] [levelValue: 800] [[
WebModule[null] ServletContext.log():Marking servlet a.b.war.HelloServlet as unavailable]]
[2017-02-14T22:03:00.334+0100] [Payara 4.1] [WARNING] [] [javax.enterprise.web] [tid: _ThreadID=25 _ThreadName=http-listener-1(2)] [timeMillis: 1487106180334] [levelValue: 900] [[
StandardWrapperValve[a.b.war.HelloServlet]: Allocate exception for servlet a.b.war.HelloServlet
org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type PersonMapper with qualifiers @Default
at injection point [BackedAnnotatedField] @Inject private a.b.war.HelloServlet.personMapper
at a.b.war.HelloServlet.personMapper(HelloServlet.java:0)
This is my test servlet:
@WebServlet("/servlet")
public class HelloServlet extends HttpServlet {
@Inject
private PersonMapper personMapper;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println(personMapper.getPerson(1L).toString());
}
My mapper class:
@Mapper
public interface PersonMapper {
@Select("SELECT * FROM person WHERE id = #{id}")
Person getPerson(@Param("id") long id);
}
It seems that MyBatisSQLSessionFactory.getSqlSessionFactory() method is never called because I cannot see anything in my log file.
My SessionFactory class:
public class MyBatisSQLSessionFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(MyBatisSQLSessionFactory.class);
@Produces
@ApplicationScoped
@SessionFactoryProvider
public SqlSessionFactory getSqlSessionFactory() throws IOException {
LOGGER.info("MyBatis is initializing...");
String resource = "mybatis-configuration.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
LOGGER.info("MyBatis has been initialized, SQL Session Factory: {}", sqlSessionFactory.toString());
return sqlSessionFactory;
}
}
And finally the structure of my war:
*.war
│ index.html
│
├───META-INF
│ │ bean.xml
│ │ MANIFEST.MF
│ │
│ └───maven
│ ...
│
└───WEB-INF
├───classes
│ └───a
│ └───b
│ └───war
│ │ HelloServlet.class
│ │
│ └───mybatis
│ │ MyBatisSQLSessionFactory.class
│ │
│ └───dao
│ PersonMapper.class
│
└───lib
Maybe I made a mistake and I forgot something...
UPDATE-2
"Weld does not detect the mapper if not used by at least one proper CDI bean. And Servlet is not proper CDI bean. Workaround is to annotate the servlet with @Dependent." You can find more details here.