@Inject在AttributeConverter中不工作

问题描述:

我有一个简单的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工作,豆必须符合这里描述的条件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://*.com/questions/12080317/inject-only-working-for-pojos-created-by-cdi-container – MWiesner

+0

部分它是重复的,但是有一个特定的Spring提供的解决方案不适用于我,因为我没有使用Spring。我用一些新的经验扩展了我的案例的描述,但问题仍未解决。 – Svetoslav

好,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也(模拟转换器)的可能性。

可惜你不能注入CDI豆成一个JPA转换器,但是在CDI 1.1可以通过编程方式注入你的加密:

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

您试图结合两个不同的世界,因为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阶段中的静态类属性。然后,您只需使用静态Repository而不是注入字段(当用作JPA Converter时,它仍然是NULL)。

仅供参考,JPA 2.2将允许CDI与AttributeConverter一起使用,并且一些供应商已经支持这个(EclipseLink,DataNucleus JPA是我所知道的那样做的)。