2014-04-10 3 views
8

나는 다음과 같은 코드를 사용하고 있습니다 :CDI @Produces와의 모호한 종속성 - 왜?

public Configuration { 

    private boolean isBatmanCar = someMethod(...); 

    @Produces 
    public Car getCar(@New Car car) { 
     if(isBatmanCar) { 
      car.setName("BatmanCar"); 
     } 
     return car; 
    } 
} 

public Car { 
    private String name = "NormalCar"; 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

public Demo { 
    @Inject 
    Car car; 

    // rest of code 
} 

나는 내가 아는

AmbiguousResolutionException: WELD-001318 Cannot resolve an ambiguous dependency between (...) Car with qualifiers [@Any @Default] (...) Producer Method [Car] with qualifiers [@Any @Default]

수 (BTW 자바 EE 6) 글래스 피시하기 위해 응용 프로그램을 배포 할 때 나는 자동차 클래스에 @Alternative를 추가 할 때 그것은 효과가 있지만, 이것이 올바른 방법인지 궁금하다. 왜 그것을해야만 하는가?

그런 경우 @Produces의 올바른 사용법을 알려주실 수 있습니까?

나는 자바 EE 6, CDI 1.0, EJB 3.1, 글래스 피시 3.2

답변

12

오류는 두 클래스 인 유형 Car, 하나의 콩, 다른 하나는 프로듀서를 가지고 있다는 사실에서 비롯를 사용하고 있습니다.

먼저 로직을 isBatmanCar 필드의 원래 클래스 (생성자 또는 @PostConstruct 메소드)에 넣고 생성자를 제거합니다. 그것은 오직 하나의 Car 빈만을 남기게됩니다.

또는 당신은 정말이 빈을 갖고 싶어하거나 당신이 당신의 생산 콩의 규정을 만들어야합니다 그것을 피할 수없는 경우 :

@Target({ TYPE, METHOD, PARAMETER, FIELD }) 
@Retention(RUNTIME) 
@Documented 
@Qualifier 
public @interface BatmanChecked { 
} 

및 생산에 사용에

@Produces 
@BatmanChecked 
public Car getCar(Car car) {...} 

을 자동차 유형을 주입 할 수 있어야합니다.

@Inject 
Car stdCar; 

@Inject 
@BatmanChecked 
Car batCheckedCar; 

한정어는 모호한 주입을 해결하는 자연적인 옵션입니다. @Alternative을 사용해도 작동하지만 좋은 연습보다 더 트릭입니다.

Car 범위가 없으므로 여기에 @New은 필요하지 않습니다. 따라서 @Dependent 범위가 지정됩니다. @New는 생산자가 @Dependent이 아닌 범위의 bean을 삽입 할 때만 유용합니다. 즉,이 코드는 Car 클래스가 범위 @Dependent에있는 경우 매우 유용하지 않습니다.

+0

@Alternative를 사용하는 좋은 방법은 무엇입니까? – dmydlarz

+0

@Alternative는 동일한 빈 (유형)에 대해 다른 버전을 제안하고 구성 파일의 구성별로 활성화 할 수있게합니다. dev/test와 production에서 다른 벤을 사용하는 경우에 유용 할 수 있습니다. 예를 들어 beans.xml 파일에서만 변경할 수 있습니다. –

5

또 다른 가능성은이 같은 자동차 클래스가 아닌 기본 생성자를 생성하는 것입니다 :

public Car { 
    private String name = "NormalCar"; 

    public Car(String name) { 
     this.name = name; 
    } 
    ... 
} 

기본 생성자를 제거하여, 자동차 클래스가 더 이상 주입에 의해 사용되는 인스턴스를 만드는 데 사용할 수 없습니다.

그리고

@Produces 
public Car getCar() { 
    if(isBatmanCar) { 
     return new Car("BatmanCar"); 
    } 
    return new Car("NormalCar"); 
} 

로 생산자 방식 변경은 생산자 방식은 자동차를 만들 수있는 유일한 방법이 될 것입니다.

이 방법은 사용자 정의 된 인스턴스가 필요하고 기본 생성자가 필요 없다는 것을 알고있을 때 사용할 수 있습니다. 하지만 보통 앙투안 솔루션이 더 유용합니다.

8

@Alternative는 사용하지만 beans.xml을 통해 활성화 할 수 있어야하는 경우에만 사용해야합니다.

빈의 기본 생성자를 억제해도 작동하지만 @RequestScoped가 아닌 다른 범위에서 빈을 사용할 수 없습니다.

독자적인 한정자를 사용하면 작동하지만 단 하나의 구현 만 있고 생성자가 아닌 생성자로 bean을 인스턴스화 할 수 있으면 매우 유용하지는 않습니다. 당신이 명심해야

@Any 
public class Car { 
} 
... 
@Produces 
public Car getCar() { 
    return new Car(); 
} 
... 
@Inject 
Car car; 

것들 :

  • 모든 콩 생산자는 항상 내재적으로 규정됩니다 @Any
  • 가장 쉬운 방법은 빈 주석을 @Any입니다 명시 적 한정자가없는 콩 및 생성자는 암시 적으로 수식 됨 @Default

  • 명시 적 한정자가있는 bean 및 제작자는 더 이상 암시 적으로 qualif가 아닙니다. IED @Default
  • 는 명시 적 규정이없는
  • 주입 지점은 내재적으로 규정 @Default하지만이 모든 관련하여

을 @Any하지,이 같은 동일한 코드 위와 같이 명시 적으로 규정 외모 :

@Any 
public class Car { 
} 
... 
@Produces 
@Any 
@Default 
public Car getCar() { 
    return new Car(); 
} 
... 
@Inject 
@Default 
Car car; 

그것을 빈의 기본 생성자가 주입 지점에 대한 유효한 가능성이 아니며 생산자가 유효한 가능성이라는 것이 더욱 명백해진다.

관련 문제