我想知道Hibernate是否可以执行ColumnTransformer的程序化配置? [英] I would like to know if there is a way with Hibernate to perform a programmatic configuration of ColumnTransformer ?

查看:369
本文介绍了我想知道Hibernate是否可以执行ColumnTransformer的程序化配置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前有一个这样的字段:

I currently have a field annotated like this :

ColumnTransformer(
          read="AES_DECRYPT(C_first_name, 'yourkey')",
          write="AES_ENCRYPT(?, 'yourkey')")
public String getFirstName() {
   return firstName;
}

这在Mysql数据库上正常工作,但是我需要此配置是可选的,因为我们的应用程序可以根据启动参数使用另一个数据库(HsqlDB).因此,我需要的是一种仅在使用特定的开始参数时才使用ColumnTransformer的方法(对于HsqlDB,则不使用ColumnTransformer,而不能使用"AES_ENCRYPT")

This is working properly with a Mysql database, but I need this configuration to be optional, because our application can use another database (HsqlDB) depending on start parameters. So what I need is a way to use a ColumnTransformer only when a specific start parameter is used (and no ColumnTransformer for HsqlDB, which cant use "AES_ENCRYPT")

有人可以帮我吗?

推荐答案

我遇到了同样的问题,我希望密钥是可配置的.我为此项目找到的唯一解决方案是在运行时更新注释值.是的,我知道这听起来很糟糕,但据我所知,没有其他方法.

I had same problem, I want key to be configurable. The only solution i found for this item is to update annotation values at runtime. Yes, i know that this sounds awful, but as far as i know there is no other way.

实体类:

@Entity
@Table(name = "user")
public class User implements Serializable {
    @Column(name = "password")
    @ColumnTransformer(read = "AES_DECRYPT(password, '${encryption.key}')", write = "AES_ENCRYPT(?, '${encryption.key}')")
    private String password;
}

我实现了将$ {encryption.key}替换为其他值的类(在我的情况下是从Spring应用程序上下文加载的)

I implemented class that replaces ${encryption.key} to the some other value (in my case loaded from Spring application context)

import org.hibernate.annotations.ColumnTransformer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.Map;

import javax.annotation.PostConstruct;

@Component(value = "transformerColumnKeyLoader")
public class TransformerColumnKeyLoader {

    public static final String KEY_ANNOTATION_PROPERTY = "${encryption.key}"; 

    @Value(value = "${secret.key}")
    private String key;

    @PostConstruct
    public void postConstruct() {
        setKey(User.class, "password");
    }

    private void setKey(Class<?> clazz, String columnName) {
        try {
            Field field = clazz.getDeclaredField(columnName);

            ColumnTransformer columnTransformer = field.getDeclaredAnnotation(ColumnTransformer.class);
            updateAnnotationValue(columnTransformer, "read");
            updateAnnotationValue(columnTransformer, "write");
        } catch (NoSuchFieldException | SecurityException e) {
            throw new RuntimeException(
                    String.format("Encryption key cannot be loaded into %s,%s", clazz.getName(), columnName));
        }
    }

    @SuppressWarnings("unchecked")
    private void updateAnnotationValue(Annotation annotation, String annotationProperty) {
        Object handler = Proxy.getInvocationHandler(annotation);
        Field merberValuesField;
        try {
            merberValuesField = handler.getClass().getDeclaredField("memberValues");
        } catch (NoSuchFieldException | SecurityException e) {
            throw new IllegalStateException(e);
        }
        merberValuesField.setAccessible(true);
        Map<String, Object> memberValues;
        try {
            memberValues = (Map<String, Object>) merberValuesField.get(handler);
        } catch (IllegalArgumentException | IllegalAccessException e) {
            throw new IllegalStateException(e);
        }
        Object oldValue = memberValues.get(annotationProperty);
        if (oldValue == null || oldValue.getClass() != String.class) {
            throw new IllegalArgumentException(String.format(
                    "Annotation value should be String. Current value is of type: %s", oldValue.getClass().getName()));
        }

        String oldValueString = oldValue.toString();
        if (!oldValueString.contains(TransformerColumnKeyLoader.KEY_ANNOTATION_PROPERTY)) {
            throw new IllegalArgumentException(
                    String.format("Annotation value should be contain %s. Current value is : %s",
                            TransformerColumnKeyLoader.KEY_ANNOTATION_PROPERTY, oldValueString));
        }
        String newValueString = oldValueString.replace(TransformerColumnKeyLoader.KEY_ANNOTATION_PROPERTY, key);

        memberValues.put(annotationProperty, newValueString);
    }
}

此代码应在创建EntityManager之前运行.在我的情况下,我使用了depend-on(对于xml配置或对于Java配置的@DependsOn).

This code should be run before creating EntityManager. In my case i used depends-on (for xml config or @DependsOn for java config).

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="transformerColumnKeyLoader"> ... </bean>

这篇关于我想知道Hibernate是否可以执行ColumnTransformer的程序化配置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆