Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@Inject not working in AttributeConverter

I have a simple AttributeConverter implementation in which I try to inject an object which have to provide the conversion logic, but @Inject seem not to work for this case. The converter class looks like this:

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

When the @Converter is triggered it throws an NullPointerException because the property crypto is not being initialized from the container. Why is that?

I'm using Glassfish 4 and in all other cases @Inject works just fine.

Is it not possible to use CDI on converters?

Any help will be appreciated :)


The accent of my question is more the AttributeConverter part. I understand that for the CDI to work a bean must meet the conditions described here http://docs.oracle.com/javaee/6/tutorial/doc/gjfzi.html. I also have tried to force the CDI to work by implementing the following constructor:

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

And now I got the following exception which doesn't give me any clue:

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)
...

I even tried using @Producer or @Decorator in order to have the CDI working on that place, but I still think there is something specific with the AttributeConverter which doesn't allow CDI. So problem not solved yet.

like image 976
Svetoslav Avatar asked Jul 21 '15 21:07

Svetoslav


3 Answers

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()
like image 176
faissalb Avatar answered Oct 07 '22 17:10

faissalb


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).

like image 29
Neil Stockton Avatar answered Oct 07 '22 18:10

Neil Stockton


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>[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);
    }
}

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).

like image 42
Jakob Galbavy Avatar answered Oct 07 '22 17:10

Jakob Galbavy