2015-07-21 2 views
3

У меня есть простая реализация AttributeConverter, в которой я пытаюсь ввести объект, который должен обеспечить логику преобразования, но @Inject, похоже, не работает для этого случая. Класс конвертер выглядит следующим образом:@Inject не работает в AttributeConverter

@Converter(autoApply=false) 
public class String2ByteArrayConverter implements AttributeConverter<String, byte[]> 
{ 
    @Inject 
    private Crypto crypto; 

    @Override 
    public byte[] convertToDatabaseColumn(String usrReadable) 
    { 
     return crypto.pg_encrypt(usrReadable); 
    } 

    @Override 
    public String convertToEntityAttribute(byte[] dbType) 
    { 
     return crypto.pg_decrypt(dbType); 
    } 
} 

Когда @Converter срабатывает он бросает NullPointerException, поскольку свойство crypto не инициализируется из контейнера. Почему это?

Я использую Glassfish 4, а во всех остальных случаях @Inject работает просто отлично.

Невозможно использовать CDI на конвертерах?

Любая помощь будет оценена :)


Акцентом мой вопрос больше AttributeConverter часть. Я понимаю, что для работы CDI bean-компонент должен соответствовать условиям, описанным здесь http://docs.oracle.com/javaee/6/tutorial/doc/gjfzi.html. я также пытался заставить CDI работать, реализуя следующий конструктор:

@Inject 
public String2ByteArrayConverter(Crypto crypto) 
{ 
    this.crypto = crypto; 
} 

И теперь я получил следующее исключение, которое не дает мне никакого понятия:

2015-07-23T01:03:24.835+0200|Severe: Exception during life cycle processing 
org.glassfish.deployment.common.DeploymentException: Exception [EclipseLink-28019] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.EntityManagerSetupException 
Exception Description: Deployment of PersistenceUnit [PU_VMA] failed. Close all factories for this PersistenceUnit. 
Internal Exception: Exception [EclipseLink-7172] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.ValidationException 
Exception Description: Error encountered when instantiating the class [class model.converter.String2ByteArrayConverter]. 
Internal Exception: java.lang.InstantiationException: model.converter.String2ByteArrayConverter 
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.createDeployFailedPersistenceException(EntityManagerSetupImpl.java:820) 
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:760) 
... 

Я даже пытался используя @Producer или @Decorator для того, чтобы CDI работал на этом месте, но я все еще думаю, что есть что-то конкретное с AttributeConverter, который не позволяет CDI. Так проблема еще не решена.

+0

Возможно, дубликат: http://stackoverflow.com/questions/12080317/inject-only-working-for-pojos-created-by-cdi-container – MWiesner

+0

Частично это дубликат, но есть особенность Spring решение, которое не работает для меня, так как я не использую Spring. Я расширил описание своего дела некоторым новым опытом, но проблема все еще не решена. – Svetoslav

ответ

0

Ну CDI еще не работает AttributeConverter, который был бы самым элегантным решением, но я нашел удовлетворительное решение. Обходной путь использует @FacesConverter. К сожалению, по умолчанию CDI не работает в лица конвертеры и валидаторы либо, но благодаря Apache MyFaces CODI API вы можете заставить его работать unsing в @Advaced аннотацию :) Так что я пришел с реализацией, как это:

@Advanced 
@FacesConverter("cryptoConverter") 
public class CryptoJSFConverter implements Converter 
{ 
    private CryptoController crypto = new CryptoController(); 

    @Inject 
    PatientController ptCtrl; 

    public Object getAsObject(FacesContext fc, UIComponent uic, String value) 
    { 
     if(value != null) 
      return crypto.pg_encrypt(value, ptCtrl.getSecretKey()); 
     else 
      return null; 
    } 


    public String getAsString(FacesContext fc, UIComponent uic, Object object) 
    { 
     String res = crypto.pg_decrypt((byte[]) object, ptCtrl.getSecretKey()); 
     return res; 
    } 
} 

Введенный управляемый bean-компонент должен быть явно аннотирован @Named и некоторым определением области. Декларация в faces-config.xmlне работа! В моем решении это выглядит так:

@Named 
@SessionScoped 
public class PatientController extends PersistanceManager 
{ 
    ... 
} 

Теперь в конвертере есть контекстная информация. В моем случае это криптографическая конфигурация, специфичная для сеанса/пользователя.

Конечно, в таком растворе, весьма вероятно, что обычай @FacesValidator также необходим, но благодаря CODI один имеет возможность использования CDI здесь также (аналог преобразователю).

4

К сожалению, вы не можете вводить CDI бобы в конвертер JPA, однако в CDI 1.1 вы можете придать свой Crypto программно:

Crypto crypto = javax.enterprise.inject.spi.CDI.current().select(Crypto.class).get() 
1

Вы пытаетесь объединить два разных мира, поскольку CDI не знает о JPA Stuff и наоборот. (Один аннотация анализатора, конечно, не знает о других) Что вы можете сделать, это:

/** 
* @author Jakob Galbavy <code>[email protected]</code> 
*/ 
@Converter 
@Singleton 
@Startup 
public class UserConverter implements AttributeConverter<User, Long> { 
    @Inject 
    private UserRepository userRepository; 
    private static UserRepository staticUserRepository; 

    @PostConstruct 
    public void init() { 
     staticUserRepository = this.userRepository; 
    } 

    @Override 
    public Long convertToDatabaseColumn(User attribute) { 
     if (null == attribute) { 
      return null; 
     } 
     return attribute.getId(); 
    } 

    @Override 
    public User convertToEntityAttribute(Long dbData) { 
     if (null == dbData) { 
      return null; 
     } 
     return staticUserRepository.findById(dbData); 
    } 
} 

Таким образом, вы можете создать Singleton EJB, который создается при загрузке контейнера, установка атрибут статического класса в фазе PostConstruct. Затем вы просто используете статический репозиторий вместо введенного поля (который будет по-прежнему оставаться NULL, когда он используется как конвертер JPA).

1

Для справки JPA 2.2 позволит использовать CDI с AttributeConverter, и некоторые поставщики уже поддерживают это (EclipseLink, DataNucleus JPA - это те, которые я знаю, которые это делают).

Смежные вопросы