如何解决这个反射错误? java.lang.reflect.Field.get(Field.java:393)
How to resolve this reflection error? java.lang.reflect.Field.get(Field.java:393)
我正在尝试在运行时更改@ColumnTransformer 的值,以便我可以将我的加密密钥存储在服务器上的其他位置。我怎样才能做到这一点?
下面是我的主要代码:
List<Field> fields = Arrays.asList(User.class.getDeclaredFields());
for(Field field:fields)
{
if(field.toString().endsWith("secretfield"))
{
System.out.println(field);
List<Annotation> annotations = Arrays.asList(field.getDeclaredAnnotations());
for(Annotation annotation : annotations)
{
if(annotation.annotationType().toString().endsWith("ColumnTransformer"))
{
Annotation newAnnotation = new ColumnTransformer(){
@Override
public String forColumn() {
return "secretfield";
}
@Override
public String read(){
return "This is Sparta";
}
@Override
public String write(){
return "This is also sparta";
}
@Override
public Class<? extends Annotation> annotationType() {
return annotation.annotationType();
}
};
Field field1 = User.class.getDeclaredField("secretfield");
field1.setAccessible(true);
Map<Class<? extends Annotation>, Annotation> annotations1 = (Map<Class<? extends Annotation>, Annotation>) field1.get(User.class);
annotations1.put(ColumnTransformer.class, newAnnotation);
}
}
}
}
下面是我的 Pojo:
package Model;
import org.hibernate.annotations.ColumnTransformer;
import javax.persistence.*;
import javax.sql.rowset.serial.SerialBlob;
import java.sql.Blob;
import java.io.Serializable;
@Entity(name = "user")
@Table(name = "user")
public class User implements Serializable {
@Column(name = "secretfield", nullable = true)
@ColumnTransformer(read = "TEST")
private String secretfield;
public String getSecretfield() {
return secretfield;
}
public void setSecretfield(String secretfield) {
this.secretfield = secretfield;
}
}
我收到这个错误:
Exception in thread "main" java.lang.IllegalArgumentException: Can not set java.lang.String field Model.User.secretfield to null value
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:393)
at Runner.main(Runner.java:65)
这一行
Map<Class<? extends Annotation>, Annotation> annotations1 = (Map<Class<? extends Annotation>, Annotation>) field1.get(User.class);
不正确。 field1.get
正在检索字段值,而不是注释图。
因为你只需要修改注解里面的参数,你真的不需要创建一个新的实例ColumnTransformer
。详情请参考Modify a class definition's annotation string parameter at runtime
changeAnnotationValue
稍微修改以修复由于 ColumnTransformer
缺少默认值而导致的 NPE,如下所示。
import org.hibernate.annotations.ColumnTransformer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.Map;
public class FieldGetAnnotation {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Field field = User.class.getDeclaredField("secretfield");
field.setAccessible(true);
final ColumnTransformer fieldAnnotation = field.getAnnotation(ColumnTransformer.class);
System.out.println("old FieldAnnotation = " + fieldAnnotation.forColumn());
changeAnnotationValue(fieldAnnotation, "forColumn", "secretfield");
System.out.println("modified FieldAnnotation = " + fieldAnnotation.forColumn());
System.out.println("old FieldAnnotation = " + fieldAnnotation.read());
changeAnnotationValue(fieldAnnotation, "read", "This is Sparta");
System.out.println("modified FieldAnnotation = " + fieldAnnotation.read());
System.out.println("old FieldAnnotation = " + fieldAnnotation.write());
changeAnnotationValue(fieldAnnotation, "write", "This is also sparta");
System.out.println("modified FieldAnnotation = " + fieldAnnotation.write());
}
@SuppressWarnings("unchecked")
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue) {
Object handler = Proxy.getInvocationHandler(annotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
Object oldValue = memberValues.get(key);
if (oldValue != null && oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException();
}
memberValues.put(key, newValue);
return oldValue;
}
}
我正在尝试在运行时更改@ColumnTransformer 的值,以便我可以将我的加密密钥存储在服务器上的其他位置。我怎样才能做到这一点?
下面是我的主要代码:
List<Field> fields = Arrays.asList(User.class.getDeclaredFields());
for(Field field:fields)
{
if(field.toString().endsWith("secretfield"))
{
System.out.println(field);
List<Annotation> annotations = Arrays.asList(field.getDeclaredAnnotations());
for(Annotation annotation : annotations)
{
if(annotation.annotationType().toString().endsWith("ColumnTransformer"))
{
Annotation newAnnotation = new ColumnTransformer(){
@Override
public String forColumn() {
return "secretfield";
}
@Override
public String read(){
return "This is Sparta";
}
@Override
public String write(){
return "This is also sparta";
}
@Override
public Class<? extends Annotation> annotationType() {
return annotation.annotationType();
}
};
Field field1 = User.class.getDeclaredField("secretfield");
field1.setAccessible(true);
Map<Class<? extends Annotation>, Annotation> annotations1 = (Map<Class<? extends Annotation>, Annotation>) field1.get(User.class);
annotations1.put(ColumnTransformer.class, newAnnotation);
}
}
}
}
下面是我的 Pojo:
package Model;
import org.hibernate.annotations.ColumnTransformer;
import javax.persistence.*;
import javax.sql.rowset.serial.SerialBlob;
import java.sql.Blob;
import java.io.Serializable;
@Entity(name = "user")
@Table(name = "user")
public class User implements Serializable {
@Column(name = "secretfield", nullable = true)
@ColumnTransformer(read = "TEST")
private String secretfield;
public String getSecretfield() {
return secretfield;
}
public void setSecretfield(String secretfield) {
this.secretfield = secretfield;
}
}
我收到这个错误:
Exception in thread "main" java.lang.IllegalArgumentException: Can not set java.lang.String field Model.User.secretfield to null value
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:393)
at Runner.main(Runner.java:65)
这一行
Map<Class<? extends Annotation>, Annotation> annotations1 = (Map<Class<? extends Annotation>, Annotation>) field1.get(User.class);
不正确。 field1.get
正在检索字段值,而不是注释图。
因为你只需要修改注解里面的参数,你真的不需要创建一个新的实例ColumnTransformer
。详情请参考Modify a class definition's annotation string parameter at runtime
changeAnnotationValue
稍微修改以修复由于 ColumnTransformer
缺少默认值而导致的 NPE,如下所示。
import org.hibernate.annotations.ColumnTransformer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.Map;
public class FieldGetAnnotation {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Field field = User.class.getDeclaredField("secretfield");
field.setAccessible(true);
final ColumnTransformer fieldAnnotation = field.getAnnotation(ColumnTransformer.class);
System.out.println("old FieldAnnotation = " + fieldAnnotation.forColumn());
changeAnnotationValue(fieldAnnotation, "forColumn", "secretfield");
System.out.println("modified FieldAnnotation = " + fieldAnnotation.forColumn());
System.out.println("old FieldAnnotation = " + fieldAnnotation.read());
changeAnnotationValue(fieldAnnotation, "read", "This is Sparta");
System.out.println("modified FieldAnnotation = " + fieldAnnotation.read());
System.out.println("old FieldAnnotation = " + fieldAnnotation.write());
changeAnnotationValue(fieldAnnotation, "write", "This is also sparta");
System.out.println("modified FieldAnnotation = " + fieldAnnotation.write());
}
@SuppressWarnings("unchecked")
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue) {
Object handler = Proxy.getInvocationHandler(annotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
Object oldValue = memberValues.get(key);
if (oldValue != null && oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException();
}
memberValues.put(key, newValue);
return oldValue;
}
}