型解決

静的な型解決 @Qualifiler

動的な型解決 @Produces

★複数の実装クラスの曖昧さを解決する方法

1.カスタムの限定子(@Qualifier)タイプを定義して関係づける

import static java.lang.annotation.ElementType.TYPE;

import static java.lang.annotation.ElementType.FIELD;

import static java.lang.annotation.ElementType.PARAMETER;

import static java.lang.annotation.ElementType.METHOD;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;

import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier

@Retention(RUNTIME)

@Target({METHOD, FIELD, PARAMETER, TYPE})

public @interface MyQualifier {}

@Inject

@MyQualifier

CustomerDAO customerDAO;

或いは

@Inject

public SomeClass(@MyQualifier CustomerDAO customerDAO) {

this.customerDAO = customerDAO;

}

@MyQualifier

public class JPACustomerDAOImpl implements CustomerDAO {...}

public class XmlCustomerDAOImpl implements CustomerDAO {...}

2.標準の限定子@Newを用いて、クラス名で関係づける

※Deprecated in CDI 1.1. @Dependent scoped beans instead

import javax.enterprise.inject.New;

@Inject

@New(JPACustomerDAOImpl.class)

CustomerDAO customerDAO;

public class JPACustomerDAOImpl implements CustomerDAO {...}

public class XmlCustomerDAOImpl implements CustomerDAO {...}

3.標準の限定子@Namedを用いて、名前(文字列)で関係づける

import javax.inject.Named;

@Inject

@Named("jpaDao")

CustomerDAO customerDAO;

@Named("jpaDao")

public class JPACustomerDAOImpl implements CustomerDAO {...}

@Named("xmlDao")

public class XmlCustomerDAOImpl implements CustomerDAO {...}

4.標準の@Alternativeを用いて、beans.xmlから指定する

import javax.enterprise.inject.Alternative;

@Inject

CustomerDAO customerDAO;

@Alternative

public class JPACustomerDAOImpl implements CustomerDAO {...}

@Alternative

public class XmlCustomerDAOImpl implements CustomerDAO {...}

beans.xmlに明示がない場合:JPACustomerDAOImpl(プロダクション用)

beans.xmlに明示がある場合:XmlCustomerDAOImpl(単体テストモック用)

@Inject

CustomerDAO customerDAO;

public class JPACustomerDAOImpl implements CustomerDAO {...}

@Alternative

public class XmlCustomerDAOImpl implements CustomerDAO {...}

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://java.sun.com/xml/ns/javaee"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="

http://java.sun.com/xml/ns/javaee

http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

<alternatives>

<class>com.example.dao.JPACustomerDAOImpl</class>

</alternatives>

</beans>

サンプル(テスト用)

@Stereotype

@Retention(RUNTIME)

@Target(TYPE)

@Alternative

public @interface Mock {}

★@Producesについて

サンプル1

import javax.annotation.PostConstruct;

import javax.enterprise.context.SessionScoped;

import javax.enterprise.inject.Instance;

import javax.inject.Inject;

import javax.inject.Named;

@Named(value = "xxx")

@SessionScoped

public class MyManagedBean implements Serializable {

@Inject

@MyRandom

Instance<Integer> randomNumber;

@Inject

@MyMaxNumber

private int maxNumber;

@PostConstruct

public void reset() {

...

this.number = randomNumber.get();

}

}

import java.util.Random;

import javax.enterprise.context.ApplicationScoped;

import javax.enterprise.inject.Produces;

@ApplicationScoped

public class Generator implements Serializable {

private Random random = new Random(System.currentTimeMillis());

private int maxNumber = 100;

@Produces

@MyRandom

public int nextNumber() {

return this.random.nextInt(maxNumber);

}

@Produces

@MyaxNumber

public int getMaxNumber() {

return this.maxNumber;

}

}

@Qualifier

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD)

public @interface MyMaxNumber / MyRandom {

}

サンプル2

@Named(value = "xxx")

public class MyManagedBean {

@Inject

@MyQualifier

private IService service;

...

}

@SessionScoped

@Named("generator")

public class Generator implements Serializable {

private int serviceType;

public void changeService(int value) {

this.serviceType = value;

}

@Produces

@MyQualifier

public IService getService() {

IService service = null;

switch (this.serviceType) {

case 0:

service = new AService();

break;

case 1:

service = new BService();

break;

default:

break;

}

return service;

}

}

サンプル3

@SessionScoped

public class MessageSenderFactory implements Serializable {

@Produces

@MessageTransport(MessageTransportType.EMAIL)

public MessageSender getEmailMessageSender(){

return new EmailMessageSender();

}

...

}

@Inject

@MessageTransport(MessageTransportType.EMAIL)

private MessageSender messageSender;

public enum MessageTransportType {

EMAIL, SMS;

}

@Qualifier

@Retention(RUNTIME)

@Target({FIELD, TYPE, METHOD})

public @interface MessageTransport {

MessageTransportType value();

}

サンプル4

@Path("/charge")

public class ChargeResource {

@Inject

@Credit

private ChargeService service;

...

}

@RequestScoped

public class PaymentStrategy {

private PaymentType type;

@Credit

@Produces

public ChargeService getStrategy(AService a, BService b) {

switch (type) {

case APayment: return a;

case BPayment: return b;

...

}

...

}

}

★Disposeについて

サンプル1

@Inject

private Connection conn; // ConnectionImpl

public class ConnectionFactory {

@Produces

@MyConnection

public Connection createConnection() {

conn.connect();

return conn;

}

public void closeConnection(

@Disposes @MyConnection Connection conn) {

conn.close();

}

}

@Inject

@MyConnection

private Connection connection;

サンプル2

import org.apache.ibatis.session.SqlSession;

@Stateless

public class MyService {


@Inject

private SqlSession session;


public List<XXX> doSomething() {

...

}

}

@Produces

@RequestScoped

public SqlSession openSession() {

...

}

// リクエスト毎にクローズされる

public void closeSession(@Disposes SqlSession sqlSession) {

sqlSession.close();

}

<alternatives>

<stereotype>xxx.cdi.stereotype.Mock</stereotype>

</alternatives>

補足 @Specializesについて

@Dependent

public class DefaultLocaleResolver implements LocaleResolver {

@Override

public Locale getLocale() {

return Locale.getDefault();

}

}

@ApplicationScoped

@Specializes

public class TestLocalResolver extends DefaultLocaleResolver {

@Override

public Locale getLocale() {

return Locale.ENGLISH;

}

}

★Qualifierの数を削減

@Qualifier

@Retention(RUNTIME)

@Target({FIELD, TYPE, METHOD, PARAMETER})

public @interface Transport {

TransportType type() default TransportType.STANDARD;

或いは

TransportType value();

}

public enum TransportType {

JSON, SOAP, STANDARD;

}

@Transport(type=TransportType.JSON)

//@Transport(TransportType.JSON)

public class MyImpl implements MyInterface {

@Inject

@Transport(type=TransportType.JSON)

//@Transport(TransportType.JSON)

private MyInterface service;

改善

@Inject @Named("persistent")

MessageSession session;

@Named("persistent")

public class PersistentMessageSession implements MessageSession {...}

或いは

@EJB(beanName="TransientMessageSession")

MessageSession session;

@Stateless

@Local(MessageSession.class)

public class TransientMessageSession implements MessageSession {...}

@Qualifier

@Retention(RUNTIME)

@Target({FIELD, TYPE})

public @interface MySession {

Type value();

enum Type{

TRANSIENT, PERSISTENT

}

}

@Inject @Session(MySession.Type.TRANSIENT)

MessageSession session;

@Session(MySession.Type.TRANSIENT)

public class TransientMessageSession implements MessageSession {...}