@Inject无法在AttributeConverter中工作

时间:2015-07-21 21:18:52

标签: jpa glassfish converter cdi

我有一个简单的AttributeConverter实现,我尝试注入一个必须提供转换逻辑的对象,但@Inject似乎不适用于这种情况。转换器类看起来像这样:

@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。所以问题还没有解决。

4 个答案:

答案 0 :(得分:6)

不幸的是,您无法将CDI bean注入JPA转换器,但是在CDI 1.1中,您可以通过编程方式注入加密:

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

你正试图结合两个不同的世界,因为CDI不知道JPA Stuff,反之亦然。 (一个注释解析器当然不知道另一个) 你能做什么,是这样的:

/**
 * @author Jakob Galbavy <code>jg@chex.at</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阶段设置静态class属性。然后,您只需使用静态存储库而不是注入的字段(当用作JPA转换器时,它仍然是NULL)。

答案 3 :(得分:0)

嗯, CDI 仍然不适用于 AttributeConverter ,这将是最优雅的解决方案,但我找到了令人满意的解决方法。解决方法是使用@FacesConverter。不幸的是,每个默认CDI在 faces转换器验证器中都不起作用,但是由于Apache MyFaces CODI API,您可以使其无效{{1注释:)所以我提出了这样的实现:

@Advaced

注入的托管bean必须使用@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; } } 和一些范围定义进行显式注释。 @Named 中的声明无效!在我的解决方案中,它看起来像这样:

faces-config.xml

现在,转换器中有一个上下文信息。在我的例子中,它是会话/用户特定的加密配置。

当然在这样的解决方案中,很可能还需要自定义@Named @SessionScoped public class PatientController extends PersistanceManager { ... } ,但是由于 CODI ,人们也可以在这里使用CDI(模拟到转换器)