Java 避免在加载时实例化存储包含null的@Embedded字段?
如果不带Java 避免在加载时实例化存储包含null的@Embedded字段?,java,hibernate,jpa,jpa-2.1,Java,Hibernate,Jpa,Jpa 2.1,如果不带地址的人员被保留并在以后加载,人员包含一个地址,所有字段都设置为空 此(修改后的)示例取自,其中报告了类似的问题 @Embeddable public class Address { private String street; private String postalCode; } @Entity public class Person { private String name; @Embedded private Address home; } 我怎样才能
地址的人员
被保留并在以后加载,人员
包含一个地址
,所有字段都设置为空
此(修改后的)示例取自,其中报告了类似的问题
@Embeddable
public class Address {
private String street;
private String postalCode;
}
@Entity
public class Person {
private String name;
@Embedded
private Address home;
}
我怎样才能避开这个问题?如果所有字段均为null
,是否可以指示Hibernate不要实例化嵌入的@对象
更改每个@Embedded
字段的getter似乎很麻烦,而且容易出错。另一个麻烦的替代方法是使用@PostLoad
,但这只是为@实体调用的,而不是为@可嵌入的调用的。好吧,我写了一些对我的情况有帮助的东西。我用@PostLoad
将其添加到@Entity
s,并使用@embeddeble
s:
public class NullableEmbeddedCleanerImpl implements NullableEmbeddedCleaner {
private final static Logger LOGGER = LoggerFactory.getLogger(NullableEmbeddedCleaner.class);
Map<Class<?>, Predicate<Object>> classFilterForNullables = new HashMap<>();
Map<Class<?>, Predicate<Object>> collectionMap = new HashMap<>();
Set<Class<?>> primitiveArrayClasses = new HashSet<Class<?>>();
public NullableEmbeddedCleanerImpl() {
fillPredicates();
fillCollectionMap();
fillPrimitiveArrayClasses();
}
/**
* B C D F I J S Z
*/
private void fillPrimitiveArrayClasses() {
try {
primitiveArrayClasses.addAll(Arrays.asList(Class.forName("[B"), Class.forName("[B"), Class.forName("[C"),
Class.forName("[D"), Class.forName("[F"), Class.forName("[I"), Class.forName("[J"), Class.forName("[S"),
Class.forName("[Z")));
} catch (ClassNotFoundException e) {
LOGGER.error("Class not found", e);
}
}
@SuppressWarnings("unchecked")
private void fillCollectionMap() { // misses Lists, Maps, ...
collection(Set.class, s -> {
final Set<Object> toRemove = new HashSet<>();
for (Object i : s) {
try {
if (clean(i)) {
toRemove.add(i);
}
} catch (Exception e) {
LOGGER.warn("Error cleaning embeddable {} : {}", e, i);
}
}
s.removeAll(toRemove);
return s.isEmpty();
});
}
@Override
public final void embeddables(Object... arg) {
for (Object i : arg) {
try {
clean(i);
} catch (IllegalArgumentException | IllegalAccessException e) {
LOGGER.warn("Error cleaning embeddable {} : {}", e, i);
}
}
}
@Override
public final boolean clean(Object arg) throws IllegalArgumentException, IllegalAccessException {
if (arg == null) {
return true;
}
boolean cleanThis = true;
Vector<Field> fields = new Vector<>();
for (Class<?> clazz = arg.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
}
for (Field field : fields) {
if (!fieldLoop(field, arg)) {
cleanThis = false;
}
}
return cleanThis;
}
private boolean fieldLoop(Field field, Object arg) throws IllegalArgumentException, IllegalAccessException {
if (Modifier.isStatic(field.getModifiers())) { // skip static fields
return true;
}
field.setAccessible(true);
Object fieldValue = field.get(arg);
if (fieldValue == null) {
return true;
}
Class<?> fieldsClass = field.getType();
if (fieldsClass.isPrimitive() || fieldsClass.isEnum()) {
return false; // can not clean primitives nor enums
}
if (fieldsClass.isArray()) {
if (primitiveArrayClasses.contains(fieldsClass)) {
return false; // ignore primitive arrays
} else {
throw new UnsupportedOperationException("Do something useful here"); // object
// arrays
}
}
for (Class<?> clazz : collectionMap.keySet()) {
if (clazz.isAssignableFrom(fieldsClass)) {
boolean emptyCollection = collectionMap.get(clazz).test(fieldValue);
if (!emptyCollection) {
return false;
} else {
field.set(arg, null);
}
return true;
}
}
// test primitives. just classes, no interfaces >>
for (Class<?> fieldClass = fieldsClass; fieldClass != null; fieldClass = fieldClass.getSuperclass()) {
if (classFilterForNullables.containsKey(fieldClass)) {
Predicate<Object> handle = classFilterForNullables.get(fieldClass);
if (handle.test(fieldValue)) {
return true;
} else {
return false;
}
}
}
if (clean(field.get(arg))) { // decent to contained objects
field.set(arg, null);
} else {// non clean-able child exists
return false;
}
return true;
}
private void fillPredicates() {
nullableFilters(String.class, Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class, Void.class, LocalDateTime.class, LocalDate.class, LocalTime.class,
OffsetDateTime.class, OffsetTime.class);
classFilterForNullables.put(NullableEmbeddedCleanerImpl.class, n -> true); // always
// filter
}
private void nullableFilters(Class<?>... cs) {
for (Class<?> c : cs) {
classFilterForNullables.put(c, o -> false);
}
}
@SuppressWarnings("unchecked")
final private <T> void collection(Class<T> c, Predicate<T> fun) {
collectionMap.put((Class<?>) c, ((Predicate<Object>) fun));
}
}
公共类NullableEmbeddedCleanerImpl实现NullableEmbeddedCleaner{
私有最终静态记录器Logger=LoggerFactory.getLogger(NullableEmbeddedCleaner.class);
Map,Predicate>collectionMap=newhashmap();
Set>();
公共NullEmbeddedCleanerImpl(){
填充谓词();
fillCollectionMap();
fillPrimitiveArrayClasses();
}
/**
*B C D F I J S Z
*/
private void fillPrimitiveArrayClasses(){
试一试{
primitiveArrayClasses.addAll(数组.asList(Class.forName(“[B”)、Class.forName(“[B”)、Class.forName(“[C”),
类别名称(“[D”)、类别名称(“[F”)、类别名称(“[I”)、类别名称(“[J”)、类别名称(“[S”),
类别名称(“[Z”);
}catch(classnotfounde异常){
记录器错误(“未找到类”,e);
}
}
@抑制警告(“未选中”)
私有void fillCollectionMap(){//未命中列表、映射。。。
集合(集合类,s->{
final Set toRemove=新HashSet();
用于(对象i:s){
试一试{
如果(清洁(i)){
删除。添加(i);
}
}捕获(例外e){
warn(“清除可嵌入{}:{}的错误”,e,i);
}
}
s、 removeAll(toRemove);
返回s.isEmpty();
});
}
@凌驾
公共最终无效嵌入(对象…arg){
用于(对象i:arg){
试一试{
清洁(i);
}捕获(IllegalArgumentException | IllegalAccessException e){
warn(“清除可嵌入{}:{}的错误”,e,i);
}
}
}
@凌驾
公共最终布尔清除(对象arg)抛出IllegalArgumentException、IllegalAccessException{
如果(arg==null){
返回true;
}
布尔值:该值为真;
向量场=新向量();
对于(类clazz=arg.getClass();clazz!=null;clazz=clazz.getSuperclass()){
addAll(Arrays.asList(clazz.getDeclaredFields());
}
用于(字段:字段){
如果(!fieldLoop(字段,参数)){
这个=假;
}
}
把这个还给我;
}
私有布尔fieldLoop(字段,对象参数)抛出IllegalArgumentException,IllegalAccessException{
if(Modifier.isStatic(field.getModifiers()){//跳过静态字段
返回true;
}
字段。setAccessible(true);
对象字段值=field.get(arg);
如果(fieldValue==null){
返回true;
}
类fieldsClass=field.getType();
if(fieldsClass.isPrimitive()| | fieldsClass.isEnum()){
返回false;//无法清除基元或枚举
}
if(fieldsClass.isArray()){
if(PrimitiveArrayClass.contains(fieldsClass)){
返回false;//忽略基元数组
}否则{
抛出新的UnsupportedOperationException(“在这里做一些有用的事情”);//对象
//阵列
}
}
for(类clazz:collectionMap.keySet()){
if(类别isAssignableFrom(fieldsClass)){
布尔值emptyCollection=collectionMap.get(clazz.test)(fieldValue);
如果(!emptyCollection){
返回false;
}否则{
field.set(arg,null);
}
返回true;
}
}
//测试原语。只有类,没有接口>>
for(类fieldClass=fieldsClass;fieldClass!=null;fieldClass=fieldClass.getSuperclass()){
if(classFilterForNullables.containsKey(fieldClass)){
谓词句柄=classFilterForNullables.get(fieldClass);
if(句柄测试(字段值)){
返回true;
}否则{
返回false;
}
}
}
if(clean(field.get(arg)){//delegate到包含的对象
field.set(arg,null);
}else{//存在不可清除的子项
返回false;
}
返回true;
}
私有void fillPredicates(){
nullableFilters(String.class、Boolean.class、Character.class、Byte.class、Short.class、Integer.class、Long.class、,
Float.class、Double.class、Void.class、LocalDateTime.class、LocalDate.class、LocalTime.class、,
OffsetDateTime.class、OffsetTime.class);
classFilterForNullables.put(nullableMbeddedCleanerImpl.class,n->true);//始终
//滤器
}
私有void nullableFilters(类…cs){
对于(c类: