Как устранить различия типов при использовании EL Resolver с WELD? - PullRequest
0 голосов
/ 15 апреля 2011

У меня есть общий производитель EL, который я написал, чтобы воспользоваться способностью WELD просто «заставить это работать», когда мне это нужно, и даже записать приведение типа в функцию, чтобы она гарантировала возвращение. тип соответствует точке ввода сварного шва.

Вот моя проблема: WELD разрешается из присваиваемых типов точки впрыска, т. Е. Если ваша точка впрыска является String, она будет искать только производителей с возвращаемым типом String.

Это проблематично, так как мне нужен один производитель, который позаботится о приведении типов и вернет правильно типизированный объект.

Как ключ, у меня есть метод String продюсер, который псевдоним реального производителя, и только делает тип kludging.

Это ... по крайней мере работает до тех пор, пока я не доберусь до ситуации, когда у меня будет точка ввода с типом Object, и в этом случае ВСЕ мои методы kludge И универсальный производитель ALL будут сопоставлены, создавая неоднозначное исключение зависимости, даже если я используйте @Typed для производителей.

Есть ли разумный способ обойти это, или я должен отказаться от этой идеи заставить WELD делать всю тяжелую работу за меня?

Вот пример использования этого производителя из bean-компонента обработки ошибок с областью запроса. В этом случае проблематичен RequestURI, для двух других требуются типизированные методы "kludge". Основная функция этого конкретного компонента (код не включен) состоит в том, чтобы перехватывать необработанные исключения и сообщать о них по электронной почте нам для более конкретной обработки ошибок в будущих ревизиях. Основным вариантом использования здесь является упрощение программного доступа к EL и, возможно, возможность обратной записи в EL с использованием привязки значения, хотя это невозможно в данном конкретном коде.

Я знаю, что могу сделать ниже, используя другие методы, это не главное. Реально, это положительный момент, чтобы упростить программный доступ к EL IMO, особенно когда имеешь дело с некоторыми из более экзотических областей (особенно с областью Flash), представленными в JSF 2.0. Большинство моих сценариев использования связано с областью применения Flash, но здесь небезопасно раскрывать данные, а также не являются предсказуемыми типами или типами, для которых должны быть записаны ключи, поэтому я хочу использовать этот более обобщенный метод.

   @Inject
   @ELResource("#{requestScope['javax.servlet.error.exception']}")
   protected Exception exception;

   @Inject
   @ELResource("#{requestScope['javax.servlet.error.status_code']}")
   protected String statusCode;

   @Inject
   @ELResource("#{requestScope['javax.servlet.error.request_uri']}")
   protected Object requestUri;

Вот мой квалификатор:

@Target(value = {ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface ELResource {
    @Nonbinding
    String value();
}

Производитель:

@Dependent
public class ELProducer {

    @Inject
    FacesContext facesContext;

    @Inject
    Logger log;

    @Produces
    @ELResource("")
    public Object getELResource(InjectionPoint ip) {
        log.entering(getClass().getName(), "getELResource()",new Object[] {ip});

        ExpressionFactory expFactory = facesContext.getApplication().getExpressionFactory();
        String elString = ip.getAnnotated().getAnnotation(ELResource.class).value();
        Class coercionType = resolveClass(ip);

        log.log(Level.INFO, "EL String: {0} of type: {1}", new Object[] {elString, coercionType.getName()});
        if (elString == null || elString.length() <= 0) {
            log.log(Level.SEVERE,"No EL String specified for injection");
            log.exiting(getClass().getName(), "getELResource()");
            return null;
        }

        ValueExpression ve = expFactory.createValueExpression(facesContext.getELContext(), elString, coercionType);

        if (ve != null) {
            Object retval = ve.getValue(facesContext.getELContext());
            log.log(Level.INFO,"EL Result: {0} of type: {1}",new Object[] { retval, ((retval != null) ? retval.getClass().getName() : "NULL") } );
            log.exiting(getClass().getName(), "getELResource()",new Object[] {retval} );
            return retval;
        } else {
            log.log(Level.WARNING,"Null EL Result");
            log.exiting(getClass().getName(), "getELResource()");
            return null;
        }
    }

    // TODO: There should be a better way of accomplishing the below
    @Produces
    @ELResource("")
    public String getELStringResource(InjectionPoint ip) {
        return (String)getELResource(ip);
    }

    @Produces
    @ELResource("")
    public Exception getELExceptionResource(InjectionPoint ip) {
        return (Exception)getELResource(ip);
    }

    private Class resolveClass(InjectionPoint ip) {
        Annotated annotated = ip.getAnnotated();
        Member member = ip.getMember();

        if (member instanceof Field) {
            Field field = (Field)member;
            return field.getType();
        } else if (member instanceof Constructor) {
            Constructor con = (Constructor)member;
            AnnotatedParameter ap = (AnnotatedParameter)annotated;
            return con.getParameterTypes()[ap.getPosition()];
        } else if (member instanceof Method) {
            Method method = (Method)member;
            AnnotatedParameter ap = (AnnotatedParameter)annotated;
            return method.getParameterTypes()[ap.getPosition()];
        } else {
            return null;
        }

    }
}

и ошибка:

org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type [Object] with qualifiers [@ELResource] at injection point [[field] @Inject @ELResource protected xxx.backing.ErrorHandler.requestUri]. Possible dependencies [[Producer Method [Exception] with qualifiers [@Any @ELResource] declared as [[method] @Produces @Typed @ELResource public xxx.ELProducer.getELExceptionResource(InjectionPoint)], Producer Method [String] with qualifiers [@Any @ELResource] declared as [[method] @Produces @Typed @ELResource public xxx.ELProducer.getELStringResource(InjectionPoint)], Producer Method [Object] with qualifiers [@Any @ELResource] declared as [[method] @Produces @Dependent @ELResource public xxx.ELProducer.getELResource(InjectionPoint)]]]
        at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:309)
        at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:139)
        at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:162)
        ...

1 Ответ

1 голос
/ 20 апреля 2011

Я знаю, что могу сделать ниже, используя другие методы, но это не главное.

Я очень старался, но я не управлял не чтобы комментировать, что вы теряете безопасность типов (что является одной из главных целей разработки CDI), и что оценка EL является фактором, снижающим производительность ...; -)

В любом случае, имея ( почти не ) сказал следующее:

Нет реальной возможности CDI преодолеть это.Я бы порекомендовал вам использовать определенный тип для этих EL-выражений, например ElObject или около того, который создается производителем и который сам предоставляет типобезопасные средства доступа для клиента.

Edit : Возможно, вы захотите взглянуть на Seam Solder , который обеспечивает EL-функциональность аккуратным способом ...

...