@Inject not working in AttributeConverter

空扰寡人 提交于 2019-12-01 17:51:14

Unfortunately you can't inject CDI beans into a JPA converter, however in CDI 1.1 you can inject your Crypto programmatically :

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

For reference, JPA 2.2 will allow CDI to be used with AttributeConverter, and some vendors already support this (EclipseLink, DataNucleus JPA are the ones I know of that do it).

You're trying to combine two different worlds, as CDI doesn't know about JPA Stuff and vice-versa. (One annotation parser of course doesn't know about the other) What you CAN do, is this:

/**
 * @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);
    }
}

This way, you would create a Singleton EJB, that is created on boot of the container, setting the static class attribute in the PostConstruct phase. You then just use the static Repository instead of the injected field (which will still be NULL, when used as a JPA Converter).

Well, CDI still doesn't work for AttributeConverter, which would be the most elegant solution, but I have found a satisfying workaround. The workaround is using @FacesConverter. Unfortunately per default CDI doesn't work in faces converters and validators either, but thanks to the Apache MyFaces CODI API you can make it work unsing the @Advaced annotation :) So I came up with an implementation like this:

@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;
    }   
}

The injected managed bean has to be explicitly annotated with @Named and some scope definition. A declaration in faces-config.xml doesn't work! In my solution it looks like this:

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

Now one has a context information in the converter. In my case it is session/user specific cryptography configuration.

Of course in such a solution it is very likely that a custom @FacesValidator is also needed, but thanks to CODI one have the possibility for using CDI here also (analog to converter).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!