Как мне устранить различия в типах при использовании EL-преобразователя с WELD?

#java #jsf #el #cdi #jboss-weld

#java #jsf #el #cdi #jboss-weld

Вопрос:

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

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

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

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

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

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

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

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

    @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. Можете ли вы описать, чего вы пытаетесь достичь? Один или два примера использования EL-инъекций были бы великолепны.

Ответ №1:

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

Я очень старался, но мне не удалось не прокомментировать, что вы теряете безопасность типов (что является одной из основных целей разработки CDI), и что оценка EL снижает производительность … 😉

Во всяком случае, сказав (почти не) это:

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

Редактировать: Возможно, вы захотите взглянуть на припой для швов, который обеспечивает функциональность EL аккуратным способом…

Комментарии:

1. Функциональность пайки швов чрезвычайно близка к тому, что я хочу, просто отсутствует последний шаг, который выполняет это автоматически во время впрыска. Это может быть максимально близко к тому, что я могу получить на данный момент, поэтому я ценю предложение.