HHH-13361 Refactor mappers
This commit is contained in:
parent
b5755b6945
commit
aa5bdab6ec
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.envers.internal.entities.mapper;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.hibernate.envers.exception.AuditException;
|
||||||
|
import org.hibernate.envers.internal.entities.PropertyData;
|
||||||
|
import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||||
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
|
import org.hibernate.property.access.spi.Getter;
|
||||||
|
import org.hibernate.property.access.spi.Setter;
|
||||||
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class for all entity mapper implementations.
|
||||||
|
*
|
||||||
|
* @author Chris Cranford
|
||||||
|
*/
|
||||||
|
public abstract class AbstractMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an action in a privileged block.
|
||||||
|
*
|
||||||
|
* @param block the lambda to executed in privileged.
|
||||||
|
* @param <T> the return type
|
||||||
|
* @return the result of the privileged call, may be {@literal null}
|
||||||
|
*/
|
||||||
|
protected <T> T doPrivileged(Supplier<T> block) {
|
||||||
|
if ( System.getSecurityManager() != null ) {
|
||||||
|
return AccessController.doPrivileged( (PrivilegedAction<T>) block::get );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return block.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a value from the specified object.
|
||||||
|
*
|
||||||
|
* @param propertyData the property data, should not be {@literal null}
|
||||||
|
* @param object the object for which the value should be read, should not be {@literal null}
|
||||||
|
* @param serviceRegistry the service registry, should not be {@literal null}
|
||||||
|
* @param <T> the return type
|
||||||
|
* @return the value read from the object, may be {@literal null}
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected <T> T getValueFromObject(PropertyData propertyData, Object object, ServiceRegistry serviceRegistry) {
|
||||||
|
return doPrivileged( () -> {
|
||||||
|
final Getter getter = ReflectionTools.getGetter( object.getClass(), propertyData, serviceRegistry );
|
||||||
|
return (T) getter.get( object );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a value from the specified object.
|
||||||
|
*
|
||||||
|
* @param propertyName the property name, should not be {@literal null}
|
||||||
|
* @param accessType the property access type, should not be {@literal null}
|
||||||
|
* @param object the object for hwich the value should be read, should not be {@literal null}
|
||||||
|
* @param serviceRegistry the service registry, should not be {@literal null}
|
||||||
|
* @param <T> the return type
|
||||||
|
* @return the value read from the object, may be {@literal null}
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected <T> T getValueFromObject(String propertyName, String accessType, Object object, ServiceRegistry serviceRegistry) {
|
||||||
|
return doPrivileged( () -> {
|
||||||
|
final Getter getter = ReflectionTools.getGetter( object.getClass(), propertyName, accessType, serviceRegistry );
|
||||||
|
return (T) getter.get( object );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the specified value on the object.
|
||||||
|
*
|
||||||
|
* @param propertyData the property data, should not be {@literal null}
|
||||||
|
* @param object the object for which the value should be set, should not be {@literal null}
|
||||||
|
* @param value the value ot be set, may be {@literal null}
|
||||||
|
* @param serviceRegistry the service registry, should not be {@literal null}
|
||||||
|
*/
|
||||||
|
protected void setValueOnObject(PropertyData propertyData, Object object, Object value, ServiceRegistry serviceRegistry) {
|
||||||
|
doPrivileged( () -> {
|
||||||
|
final Setter setter = ReflectionTools.getSetter(object.getClass(), propertyData, serviceRegistry );
|
||||||
|
setter.set( object, value );
|
||||||
|
return null;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value from the source object and sets the value in the destination object.
|
||||||
|
*
|
||||||
|
* @param propertyData the property data, should not be {@literal null}
|
||||||
|
* @param source the source object, should not be {@literal null}
|
||||||
|
* @param destination the destination object, should not be {@literal null}
|
||||||
|
* @param serviceRegistry the service registry, should not be {@literal null}
|
||||||
|
*/
|
||||||
|
protected void getAndSetValue(PropertyData propertyData, Object source, Object destination, ServiceRegistry serviceRegistry) {
|
||||||
|
doPrivileged( () -> {
|
||||||
|
final Getter getter = ReflectionTools.getGetter( source.getClass(), propertyData, serviceRegistry );
|
||||||
|
final Setter setter = ReflectionTools.getSetter( destination.getClass(), propertyData, serviceRegistry );
|
||||||
|
setter.set( destination, getter.get( source ) );
|
||||||
|
return null;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new object based on the specified class with the given constructor arguments.
|
||||||
|
*
|
||||||
|
* @param clazz the class, must not be {@literal null}
|
||||||
|
* @param args the variadic constructor arguments, may be omitted.
|
||||||
|
* @param <T> the return class type
|
||||||
|
* @return a new instance of the class
|
||||||
|
*/
|
||||||
|
protected <T> T newObjectInstance(Class<T> clazz, Object... args) {
|
||||||
|
return doPrivileged( () -> {
|
||||||
|
try {
|
||||||
|
final Constructor<T> constructor = ReflectHelper.getDefaultConstructor( clazz );
|
||||||
|
if ( constructor == null ) {
|
||||||
|
throw new AuditException( "Failed to locate default constructor for class: " + clazz.getName() );
|
||||||
|
}
|
||||||
|
return constructor.newInstance( args );
|
||||||
|
}
|
||||||
|
catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ package org.hibernate.envers.internal.entities.mapper;
|
||||||
*
|
*
|
||||||
* @author Chris Cranford
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractPropertyMapper implements PropertyMapper {
|
public abstract class AbstractPropertyMapper extends AbstractMapper implements PropertyMapper {
|
||||||
private boolean map;
|
private boolean map;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
package org.hibernate.envers.internal.entities.mapper;
|
package org.hibernate.envers.internal.entities.mapper;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -118,43 +116,38 @@ public class ComponentPropertyMapper extends AbstractPropertyMapper implements C
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessController.doPrivileged(
|
doPrivileged( () -> {
|
||||||
new PrivilegedAction<Object>() {
|
try {
|
||||||
@Override
|
final Object subObj = ReflectHelper.getDefaultConstructor( componentClass ).newInstance();
|
||||||
public Object run() {
|
|
||||||
try {
|
|
||||||
final Object subObj = ReflectHelper.getDefaultConstructor( componentClass ).newInstance();
|
|
||||||
|
|
||||||
if ( isDynamicComponentMap() ) {
|
if ( isDynamicComponentMap() ) {
|
||||||
( (Map) obj ).put( propertyData.getBeanName(), subObj );
|
( (Map) obj ).put( propertyData.getBeanName(), subObj );
|
||||||
delegate.mapToEntityFromMap( enversService, subObj, data, primaryKey, versionsReader, revision );
|
delegate.mapToEntityFromMap( enversService, subObj, data, primaryKey, versionsReader, revision );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final Setter setter = ReflectionTools.getSetter(
|
final Setter setter = ReflectionTools.getSetter(
|
||||||
obj.getClass(),
|
obj.getClass(),
|
||||||
propertyData,
|
propertyData,
|
||||||
enversService.getServiceRegistry()
|
enversService.getServiceRegistry()
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( isAllPropertiesNull( data ) ) {
|
if ( isAllPropertiesNull( data ) ) {
|
||||||
// single property, but default value need not be null, so we'll set it to null anyway
|
// single property, but default value need not be null, so we'll set it to null anyway
|
||||||
setter.set( obj, null );
|
setter.set( obj, null );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// set the component
|
// set the component
|
||||||
setter.set( obj, subObj );
|
setter.set( obj, subObj );
|
||||||
delegate.mapToEntityFromMap( enversService, subObj, data, primaryKey, versionsReader, revision );
|
delegate.mapToEntityFromMap( enversService, subObj, data, primaryKey, versionsReader, revision );
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch ( Exception e ) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
}
|
||||||
|
catch ( Exception e ) {
|
||||||
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAllPropertiesNull(Map data) {
|
private boolean isAllPropertiesNull(Map data) {
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
package org.hibernate.envers.internal.entities.mapper;
|
package org.hibernate.envers.internal.entities.mapper;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -101,49 +99,44 @@ public class MultiPropertyMapper extends AbstractPropertyMapper implements Exten
|
||||||
final Map<String, Object> data,
|
final Map<String, Object> data,
|
||||||
final Object newObj,
|
final Object newObj,
|
||||||
final Object oldObj) {
|
final Object oldObj) {
|
||||||
return AccessController.doPrivileged(
|
return doPrivileged( () -> {
|
||||||
new PrivilegedAction<Boolean>() {
|
boolean ret = false;
|
||||||
@Override
|
for ( Map.Entry<PropertyData, PropertyMapper> entry : properties.entrySet() ) {
|
||||||
public Boolean run() {
|
final PropertyData propertyData = entry.getKey();
|
||||||
boolean ret = false;
|
final PropertyMapper propertyMapper = entry.getValue();
|
||||||
for ( Map.Entry<PropertyData, PropertyMapper> entry : properties.entrySet() ) {
|
|
||||||
final PropertyData propertyData = entry.getKey();
|
|
||||||
final PropertyMapper propertyMapper = entry.getValue();
|
|
||||||
|
|
||||||
// synthetic properties are not part of the entity model; therefore they should be ignored.
|
// synthetic properties are not part of the entity model; therefore they should be ignored.
|
||||||
if ( propertyData.isSynthetic() ) {
|
if ( propertyData.isSynthetic() ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
Getter getter;
|
|
||||||
if ( newObj != null ) {
|
|
||||||
getter = ReflectionTools.getGetter(
|
|
||||||
newObj.getClass(),
|
|
||||||
propertyData,
|
|
||||||
session.getFactory().getServiceRegistry()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if ( oldObj != null ) {
|
|
||||||
getter = ReflectionTools.getGetter(
|
|
||||||
oldObj.getClass(),
|
|
||||||
propertyData,
|
|
||||||
session.getFactory().getServiceRegistry()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret |= propertyMapper.mapToMapFromEntity(
|
|
||||||
session, data,
|
|
||||||
newObj == null ? null : getter.get( newObj ),
|
|
||||||
oldObj == null ? null : getter.get( oldObj )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
Getter getter;
|
||||||
|
if ( newObj != null ) {
|
||||||
|
getter = ReflectionTools.getGetter(
|
||||||
|
newObj.getClass(),
|
||||||
|
propertyData,
|
||||||
|
session.getFactory().getServiceRegistry()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if ( oldObj != null ) {
|
||||||
|
getter = ReflectionTools.getGetter(
|
||||||
|
oldObj.getClass(),
|
||||||
|
propertyData,
|
||||||
|
session.getFactory().getServiceRegistry()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret |= propertyMapper.mapToMapFromEntity(
|
||||||
|
session, data,
|
||||||
|
newObj == null ? null : getter.get( newObj ),
|
||||||
|
oldObj == null ? null : getter.get( oldObj )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -152,49 +145,44 @@ public class MultiPropertyMapper extends AbstractPropertyMapper implements Exten
|
||||||
final Map<String, Object> data,
|
final Map<String, Object> data,
|
||||||
final Object newObj,
|
final Object newObj,
|
||||||
final Object oldObj) {
|
final Object oldObj) {
|
||||||
AccessController.doPrivileged(
|
doPrivileged( () -> {
|
||||||
new PrivilegedAction<Object>() {
|
for ( Map.Entry<PropertyData, PropertyMapper> entry : properties.entrySet() ) {
|
||||||
@Override
|
final PropertyData propertyData = entry.getKey();
|
||||||
public Object run() {
|
final PropertyMapper propertyMapper = entry.getValue();
|
||||||
for ( Map.Entry<PropertyData, PropertyMapper> entry : properties.entrySet() ) {
|
|
||||||
final PropertyData propertyData = entry.getKey();
|
|
||||||
final PropertyMapper propertyMapper = entry.getValue();
|
|
||||||
|
|
||||||
// synthetic properties are not part of the entity model; therefore they should be ignored.
|
// synthetic properties are not part of the entity model; therefore they should be ignored.
|
||||||
if ( propertyData.isSynthetic() ) {
|
if ( propertyData.isSynthetic() ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
Getter getter;
|
|
||||||
if ( newObj != null ) {
|
|
||||||
getter = ReflectionTools.getGetter(
|
|
||||||
newObj.getClass(),
|
|
||||||
propertyData,
|
|
||||||
session.getFactory().getServiceRegistry()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if ( oldObj != null ) {
|
|
||||||
getter = ReflectionTools.getGetter(
|
|
||||||
oldObj.getClass(),
|
|
||||||
propertyData,
|
|
||||||
session.getFactory().getServiceRegistry()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
propertyMapper.mapModifiedFlagsToMapFromEntity(
|
|
||||||
session, data,
|
|
||||||
newObj == null ? null : getter.get( newObj ),
|
|
||||||
oldObj == null ? null : getter.get( oldObj )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
Getter getter;
|
||||||
|
if ( newObj != null ) {
|
||||||
|
getter = ReflectionTools.getGetter(
|
||||||
|
newObj.getClass(),
|
||||||
|
propertyData,
|
||||||
|
session.getFactory().getServiceRegistry()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if ( oldObj != null ) {
|
||||||
|
getter = ReflectionTools.getGetter(
|
||||||
|
oldObj.getClass(),
|
||||||
|
propertyData,
|
||||||
|
session.getFactory().getServiceRegistry()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
propertyMapper.mapModifiedFlagsToMapFromEntity(
|
||||||
|
session, data,
|
||||||
|
newObj == null ? null : getter.get( newObj ),
|
||||||
|
oldObj == null ? null : getter.get( oldObj )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
package org.hibernate.envers.internal.entities.mapper;
|
package org.hibernate.envers.internal.entities.mapper;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -105,25 +103,20 @@ public class SinglePropertyMapper extends AbstractPropertyMapper implements Simp
|
||||||
map.put( propertyData.getBeanName(), value );
|
map.put( propertyData.getBeanName(), value );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AccessController.doPrivileged(
|
doPrivileged( () -> {
|
||||||
new PrivilegedAction<Object>() {
|
final Setter setter = ReflectionTools.getSetter(
|
||||||
@Override
|
obj.getClass(),
|
||||||
public Object run() {
|
propertyData,
|
||||||
final Setter setter = ReflectionTools.getSetter(
|
enversService.getServiceRegistry()
|
||||||
obj.getClass(),
|
);
|
||||||
propertyData,
|
|
||||||
enversService.getServiceRegistry()
|
|
||||||
);
|
|
||||||
|
|
||||||
// We only set a null value if the field is not primitive. Otherwise, we leave it intact.
|
// We only set a null value if the field is not primitive. Otherwise, we leave it intact.
|
||||||
if ( value != null || !isPrimitive( setter, propertyData, obj.getClass() ) ) {
|
if ( value != null || !isPrimitive( setter, propertyData, obj.getClass() ) ) {
|
||||||
setter.set( obj, value );
|
setter.set( obj, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
} );
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.id;
|
package org.hibernate.envers.internal.entities.mapper.id;
|
||||||
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.exception.AuditException;
|
import org.hibernate.envers.exception.AuditException;
|
||||||
|
@ -66,18 +64,13 @@ public abstract class AbstractCompositeIdMapper extends AbstractIdMapper impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object instantiateCompositeId() {
|
protected Object instantiateCompositeId() {
|
||||||
return AccessController.doPrivileged(
|
return doPrivileged( () -> {
|
||||||
new PrivilegedAction<Object>() {
|
try {
|
||||||
@Override
|
return ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
|
||||||
public Object run() {
|
}
|
||||||
try {
|
catch ( Exception e ) {
|
||||||
return ReflectHelper.getDefaultConstructor( compositeIdClass ).newInstance();
|
throw new AuditException( e );
|
||||||
}
|
}
|
||||||
catch ( Exception e ) {
|
} );
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate.envers.internal.entities.mapper.id;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.envers.internal.entities.PropertyData;
|
||||||
|
import org.hibernate.envers.internal.entities.mapper.AbstractMapper;
|
||||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
|
@ -18,7 +20,7 @@ import org.hibernate.service.ServiceRegistry;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Chris Cranford
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractIdMapper implements IdMapper {
|
public abstract class AbstractIdMapper extends AbstractMapper implements IdMapper {
|
||||||
private final ServiceRegistry serviceRegistry;
|
private final ServiceRegistry serviceRegistry;
|
||||||
|
|
||||||
public AbstractIdMapper(ServiceRegistry serviceRegistry) {
|
public AbstractIdMapper(ServiceRegistry serviceRegistry) {
|
||||||
|
@ -143,6 +145,18 @@ public abstract class AbstractIdMapper implements IdMapper {
|
||||||
|
|
||||||
public abstract void mapToEntityFromEntity(Object objectTo, Object objectFrom);
|
public abstract void mapToEntityFromEntity(Object objectTo, Object objectFrom);
|
||||||
|
|
||||||
|
protected <T> T getValueFromObject(PropertyData propertyData, Object object) {
|
||||||
|
return getValueFromObject( propertyData, object, getServiceRegistry() );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setValueOnObject(PropertyData propertyData, Object object, Object value) {
|
||||||
|
setValueOnObject( propertyData, object, value, getServiceRegistry() );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void getAndSetValue(PropertyData propertyData, Object source, Object destination) {
|
||||||
|
getAndSetValue( propertyData, source, destination, getServiceRegistry() );
|
||||||
|
}
|
||||||
|
|
||||||
private void handleNullValue(Parameters parameters, String alias, String propertyName, boolean equals) {
|
private void handleNullValue(Parameters parameters, String alias, String propertyName, boolean equals) {
|
||||||
if ( equals ) {
|
if ( equals ) {
|
||||||
parameters.addNullRestriction( alias, propertyName );
|
parameters.addNullRestriction( alias, propertyName );
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.id;
|
package org.hibernate.envers.internal.entities.mapper.id;
|
||||||
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -17,7 +15,6 @@ import org.hibernate.envers.exception.AuditException;
|
||||||
import org.hibernate.envers.internal.entities.PropertyData;
|
import org.hibernate.envers.internal.entities.PropertyData;
|
||||||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
import org.hibernate.property.access.spi.Getter;
|
|
||||||
import org.hibernate.property.access.spi.Setter;
|
import org.hibernate.property.access.spi.Setter;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
|
@ -52,22 +49,7 @@ public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements Simpl
|
||||||
if ( obj == null ) {
|
if ( obj == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
mapToMapFromId( data, getValueFromObject( idPropertyData, obj ) );
|
||||||
final Object value = AccessController.doPrivileged(
|
|
||||||
new PrivilegedAction<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object run() {
|
|
||||||
final Getter getter = ReflectionTools.getGetter(
|
|
||||||
obj.getClass(),
|
|
||||||
idPropertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
return getter.get( obj );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
mapToMapFromId( data, value );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,32 +58,26 @@ public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements Simpl
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AccessController.doPrivileged(
|
return doPrivileged( () -> {
|
||||||
new PrivilegedAction<Boolean>() {
|
final Setter setter = ReflectionTools.getSetter( obj.getClass(), idPropertyData, getServiceRegistry() );
|
||||||
@Override
|
try {
|
||||||
public Boolean run() {
|
final Object subObj = instantiateCompositeId();
|
||||||
final Setter setter = ReflectionTools.getSetter( obj.getClass(), idPropertyData, getServiceRegistry() );
|
|
||||||
|
|
||||||
try {
|
boolean ret = true;
|
||||||
final Object subObj = instantiateCompositeId();
|
for ( IdMapper idMapper : ids.values() ) {
|
||||||
|
ret &= idMapper.mapToEntityFromMap( subObj, data );
|
||||||
boolean ret = true;
|
|
||||||
for ( IdMapper idMapper : ids.values() ) {
|
|
||||||
ret &= idMapper.mapToEntityFromMap( subObj, data );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ret ) {
|
|
||||||
setter.set( obj, subObj );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
if ( ret ) {
|
||||||
|
setter.set( obj, subObj );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -122,19 +98,7 @@ public class EmbeddedIdMapper extends AbstractCompositeIdMapper implements Simpl
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AccessController.doPrivileged(
|
return getValueFromObject( idPropertyData, data );
|
||||||
new PrivilegedAction<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object run() {
|
|
||||||
final Getter getter = ReflectionTools.getGetter(
|
|
||||||
data.getClass(),
|
|
||||||
idPropertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
return getter.get( data );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,17 +6,12 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.id;
|
package org.hibernate.envers.internal.entities.mapper.id;
|
||||||
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.exception.AuditException;
|
import org.hibernate.envers.exception.AuditException;
|
||||||
import org.hibernate.envers.internal.entities.PropertyData;
|
import org.hibernate.envers.internal.entities.PropertyData;
|
||||||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
|
||||||
import org.hibernate.property.access.spi.Getter;
|
|
||||||
import org.hibernate.property.access.spi.Setter;
|
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
|
@ -63,20 +58,8 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AccessController.doPrivileged(
|
setValueOnObject( propertyData, obj, value );
|
||||||
new PrivilegedAction<Boolean>() {
|
return true;
|
||||||
@Override
|
|
||||||
public Boolean run() {
|
|
||||||
final Setter setter = ReflectionTools.getSetter(
|
|
||||||
obj.getClass(),
|
|
||||||
propertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
setter.set( obj, value );
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -99,19 +82,7 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
|
||||||
return hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier();
|
return hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return AccessController.doPrivileged(
|
return getValueFromObject( propertyData, data );
|
||||||
new PrivilegedAction<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object run() {
|
|
||||||
final Getter getter = ReflectionTools.getGetter(
|
|
||||||
data.getClass(),
|
|
||||||
propertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
return getter.get( data );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,19 +104,7 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
|
||||||
data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier() );
|
data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier() );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final Object value = AccessController.doPrivileged(
|
final Object value = getValueFromObject( propertyData, obj );
|
||||||
new PrivilegedAction<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object run() {
|
|
||||||
final Getter getter = ReflectionTools.getGetter(
|
|
||||||
obj.getClass(),
|
|
||||||
propertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
return getter.get( obj );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
data.put( propertyData.getName(), value );
|
data.put( propertyData.getName(), value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,28 +115,7 @@ public class SingleIdMapper extends AbstractIdMapper implements SimpleIdMapperBu
|
||||||
if ( objTo == null || objFrom == null ) {
|
if ( objTo == null || objFrom == null ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
getAndSetValue(propertyData, objFrom, objTo );
|
||||||
AccessController.doPrivileged(
|
|
||||||
new PrivilegedAction<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object run() {
|
|
||||||
final Getter getter = ReflectionTools.getGetter(
|
|
||||||
objFrom.getClass(),
|
|
||||||
propertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
|
|
||||||
final Setter setter = ReflectionTools.getSetter(
|
|
||||||
objTo.getClass(),
|
|
||||||
propertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
|
|
||||||
setter.set( objTo, getter.get( objFrom ) );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,9 +6,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.id;
|
package org.hibernate.envers.internal.entities.mapper.id;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
|
@ -48,19 +45,7 @@ public class VirtualEntitySingleIdMapper extends SingleIdMapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mapToMapFromId(Session session, Map<String, Object> data, Object obj) {
|
public void mapToMapFromId(Session session, Map<String, Object> data, Object obj) {
|
||||||
final Serializable value = AccessController.doPrivileged(
|
final Object value = getValueFromObject( propertyData, obj );
|
||||||
new PrivilegedAction<Serializable>() {
|
|
||||||
@Override
|
|
||||||
public Serializable run() {
|
|
||||||
final Getter getter = ReflectionTools.getGetter(
|
|
||||||
obj.getClass(),
|
|
||||||
propertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
return (Serializable) getter.get( obj );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Either loads the entity from the session's 1LC if it already exists or potentially creates a
|
// Either loads the entity from the session's 1LC if it already exists or potentially creates a
|
||||||
// proxy object to represent the entity by identifier so that we can reference it in the map.
|
// proxy object to represent the entity by identifier so that we can reference it in the map.
|
||||||
|
@ -74,40 +59,35 @@ public class VirtualEntitySingleIdMapper extends SingleIdMapper {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AccessController.doPrivileged(
|
doPrivileged( () -> {
|
||||||
new PrivilegedAction<Object>() {
|
final Getter getter = ReflectionTools.getGetter(
|
||||||
@Override
|
objFrom.getClass(),
|
||||||
public Object run() {
|
propertyData,
|
||||||
final Getter getter = ReflectionTools.getGetter(
|
getServiceRegistry()
|
||||||
objFrom.getClass(),
|
);
|
||||||
propertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
|
|
||||||
final Setter setter = ReflectionTools.getSetter(
|
final Setter setter = ReflectionTools.getSetter(
|
||||||
objTo.getClass(),
|
objTo.getClass(),
|
||||||
propertyData,
|
propertyData,
|
||||||
getServiceRegistry()
|
getServiceRegistry()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get the value from the containing entity
|
// Get the value from the containing entity
|
||||||
final Object value = getter.get( objFrom );
|
final Object value = getter.get( objFrom );
|
||||||
if ( value == null ) {
|
if ( value == null ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !value.getClass().equals( propertyData.getVirtualReturnClass() ) ) {
|
if ( !value.getClass().equals( propertyData.getVirtualReturnClass() ) ) {
|
||||||
setter.set( objTo, getAssociatedEntityIdMapper().mapToIdFromEntity( value ) );
|
setter.set( objTo, getAssociatedEntityIdMapper().mapToIdFromEntity( value ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// This means we're setting the object
|
// This means we're setting the object
|
||||||
setter.set( objTo, value );
|
setter.set( objTo, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
} );
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -121,32 +101,27 @@ public class VirtualEntitySingleIdMapper extends SingleIdMapper {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AccessController.doPrivileged(
|
return doPrivileged( () -> {
|
||||||
new PrivilegedAction<Boolean>() {
|
final Setter setter = ReflectionTools.getSetter(
|
||||||
@Override
|
obj.getClass(),
|
||||||
public Boolean run() {
|
propertyData,
|
||||||
final Setter setter = ReflectionTools.getSetter(
|
getServiceRegistry()
|
||||||
obj.getClass(),
|
);
|
||||||
propertyData,
|
final Class<?> paramClass = ReflectionTools.getType(
|
||||||
getServiceRegistry()
|
obj.getClass(),
|
||||||
);
|
propertyData,
|
||||||
final Class<?> paramClass = ReflectionTools.getType(
|
getServiceRegistry()
|
||||||
obj.getClass(),
|
);
|
||||||
propertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( paramClass != null && paramClass.equals( propertyData.getVirtualReturnClass() ) ) {
|
if ( paramClass != null && paramClass.equals( propertyData.getVirtualReturnClass() ) ) {
|
||||||
setter.set( obj, getAssociatedEntityIdMapper().mapToIdFromEntity( value ) );
|
setter.set( obj, getAssociatedEntityIdMapper().mapToIdFromEntity( value ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setter.set( obj, value );
|
setter.set( obj, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
} );
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -160,19 +135,7 @@ public class VirtualEntitySingleIdMapper extends SingleIdMapper {
|
||||||
data.put( propertyData.getName(), proxy.getHibernateLazyInitializer().getInternalIdentifier() );
|
data.put( propertyData.getName(), proxy.getHibernateLazyInitializer().getInternalIdentifier() );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final Object value = AccessController.doPrivileged(
|
final Object value = getValueFromObject( propertyData, obj );
|
||||||
new PrivilegedAction<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object run() {
|
|
||||||
final Getter getter = ReflectionTools.getGetter(
|
|
||||||
obj.getClass(),
|
|
||||||
propertyData,
|
|
||||||
getServiceRegistry()
|
|
||||||
);
|
|
||||||
return getter.get( obj );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( propertyData.getVirtualReturnClass().isInstance( value ) ) {
|
if ( propertyData.getVirtualReturnClass().isInstance( value ) ) {
|
||||||
// The value is the primary key, need to map it via IdMapper
|
// The value is the primary key, need to map it via IdMapper
|
||||||
|
|
|
@ -8,8 +8,6 @@ package org.hibernate.envers.internal.entities.mapper.relation;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -30,9 +28,7 @@ import org.hibernate.envers.internal.entities.mapper.AbstractPropertyMapper;
|
||||||
import org.hibernate.envers.internal.entities.mapper.PersistentCollectionChangeData;
|
import org.hibernate.envers.internal.entities.mapper.PersistentCollectionChangeData;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor;
|
import org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor.Initializor;
|
||||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.property.access.spi.Setter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
@ -306,22 +302,7 @@ public abstract class AbstractCollectionMapper<T> extends AbstractPropertyMapper
|
||||||
map.put( collectionPropertyData.getBeanName(), collectionProxy );
|
map.put( collectionPropertyData.getBeanName(), collectionProxy );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AccessController.doPrivileged(
|
setValueOnObject( collectionPropertyData, obj, collectionProxy, enversService.getServiceRegistry() );
|
||||||
new PrivilegedAction<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object run() {
|
|
||||||
final Setter setter = ReflectionTools.getSetter(
|
|
||||||
obj.getClass(),
|
|
||||||
collectionPropertyData,
|
|
||||||
enversService.getServiceRegistry()
|
|
||||||
);
|
|
||||||
|
|
||||||
setter.set( obj, collectionProxy );
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
package org.hibernate.envers.internal.entities.mapper.relation;
|
package org.hibernate.envers.internal.entities.mapper.relation;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -21,7 +19,6 @@ import org.hibernate.envers.internal.entities.mapper.AbstractPropertyMapper;
|
||||||
import org.hibernate.envers.internal.entities.mapper.PersistentCollectionChangeData;
|
import org.hibernate.envers.internal.entities.mapper.PersistentCollectionChangeData;
|
||||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
import org.hibernate.envers.internal.tools.ReflectionTools;
|
||||||
import org.hibernate.property.access.spi.Setter;
|
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,21 +93,7 @@ public abstract class AbstractToOneMapper extends AbstractPropertyMapper {
|
||||||
map.put( propertyData.getBeanName(), value );
|
map.put( propertyData.getBeanName(), value );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
AccessController.doPrivileged(
|
setValueOnObject( propertyData, targetObject, value, serviceRegistry );
|
||||||
new PrivilegedAction<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object run() {
|
|
||||||
final Setter setter = ReflectionTools.getSetter(
|
|
||||||
targetObject.getClass(),
|
|
||||||
propertyData,
|
|
||||||
serviceRegistry
|
|
||||||
);
|
|
||||||
setter.set( targetObject, value );
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||||
|
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||||
|
*/
|
||||||
|
package org.hibernate.envers.internal.entities.mapper.relation.component;
|
||||||
|
|
||||||
|
import org.hibernate.envers.internal.entities.mapper.AbstractMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract base class for all middle component mappers.
|
||||||
|
*
|
||||||
|
* @author Chris Cranford
|
||||||
|
*/
|
||||||
|
public abstract class AbstractMiddleComponentMapper extends AbstractMapper implements MiddleComponentMapper {
|
||||||
|
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public final class MiddleDummyComponentMapper implements MiddleComponentMapper {
|
public final class MiddleDummyComponentMapper extends AbstractMiddleComponentMapper {
|
||||||
public Object mapToObjectFromFullMap(
|
public Object mapToObjectFromFullMap(
|
||||||
EntityInstantiator entityInstantiator, Map<String, Object> data,
|
EntityInstantiator entityInstantiator, Map<String, Object> data,
|
||||||
Object dataObject, Number revision) {
|
Object dataObject, Number revision) {
|
||||||
|
|
|
@ -6,9 +6,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.relation.component;
|
package org.hibernate.envers.internal.entities.mapper.relation.component;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
@ -20,16 +17,16 @@ import org.hibernate.envers.internal.entities.mapper.MultiPropertyMapper;
|
||||||
import org.hibernate.envers.internal.entities.mapper.PropertyMapper;
|
import org.hibernate.envers.internal.entities.mapper.PropertyMapper;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.ToOneIdMapper;
|
import org.hibernate.envers.internal.entities.mapper.relation.ToOneIdMapper;
|
||||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
|
* @author Kristoffer Lundberg (kristoffer at cambio dot se)
|
||||||
*/
|
*/
|
||||||
public class MiddleEmbeddableComponentMapper implements MiddleComponentMapper, CompositeMapperBuilder {
|
public class MiddleEmbeddableComponentMapper extends AbstractMiddleComponentMapper implements CompositeMapperBuilder {
|
||||||
private final MultiPropertyMapper delegate;
|
|
||||||
private final Class componentClass;
|
|
||||||
|
|
||||||
public MiddleEmbeddableComponentMapper(MultiPropertyMapper delegate, Class componentClass) {
|
private final MultiPropertyMapper delegate;
|
||||||
|
private final Class<?> componentClass;
|
||||||
|
|
||||||
|
public MiddleEmbeddableComponentMapper(MultiPropertyMapper delegate, Class<?> componentClass) {
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
this.componentClass = componentClass;
|
this.componentClass = componentClass;
|
||||||
}
|
}
|
||||||
|
@ -65,26 +62,7 @@ public class MiddleEmbeddableComponentMapper implements MiddleComponentMapper, C
|
||||||
if ( dataObject != null ) {
|
if ( dataObject != null ) {
|
||||||
return dataObject;
|
return dataObject;
|
||||||
}
|
}
|
||||||
|
return newObjectInstance( componentClass );
|
||||||
return AccessController.doPrivileged(
|
|
||||||
new PrivilegedAction<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object run() {
|
|
||||||
try {
|
|
||||||
return ReflectHelper.getDefaultConstructor( componentClass ).newInstance();
|
|
||||||
}
|
|
||||||
catch ( InstantiationException e ) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
catch ( IllegalAccessException e ) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
catch ( InvocationTargetException e ) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
*
|
*
|
||||||
* @author Chris Cranford
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public class MiddleMapElementNotKeyComponentMapper implements MiddleComponentMapper {
|
public class MiddleMapElementNotKeyComponentMapper extends AbstractMiddleComponentMapper {
|
||||||
private final String propertyName;
|
private final String propertyName;
|
||||||
|
|
||||||
public MiddleMapElementNotKeyComponentMapper(String propertyName) {
|
public MiddleMapElementNotKeyComponentMapper(String propertyName) {
|
||||||
|
|
|
@ -22,7 +22,7 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Chris Cranford
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public final class MiddleMapKeyIdComponentMapper implements MiddleComponentMapper {
|
public final class MiddleMapKeyIdComponentMapper extends AbstractMiddleComponentMapper {
|
||||||
private final Configuration configuration;
|
private final Configuration configuration;
|
||||||
private final IdMapper relatedIdMapper;
|
private final IdMapper relatedIdMapper;
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,11 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.relation.component;
|
package org.hibernate.envers.internal.entities.mapper.relation.component;
|
||||||
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
import org.hibernate.envers.internal.tools.ReflectionTools;
|
|
||||||
import org.hibernate.envers.internal.tools.query.Parameters;
|
import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
import org.hibernate.property.access.spi.Getter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component mapper for the @MapKey mapping with the name parameter specified: the value of the map's key
|
* A component mapper for the @MapKey mapping with the name parameter specified: the value of the map's key
|
||||||
|
@ -23,7 +19,7 @@ import org.hibernate.property.access.spi.Getter;
|
||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public class MiddleMapKeyPropertyComponentMapper implements MiddleComponentMapper {
|
public class MiddleMapKeyPropertyComponentMapper extends AbstractMiddleComponentMapper {
|
||||||
private final String propertyName;
|
private final String propertyName;
|
||||||
private final String accessType;
|
private final String accessType;
|
||||||
|
|
||||||
|
@ -39,19 +35,11 @@ public class MiddleMapKeyPropertyComponentMapper implements MiddleComponentMappe
|
||||||
final Object dataObject,
|
final Object dataObject,
|
||||||
Number revision) {
|
Number revision) {
|
||||||
// dataObject is not null, as this mapper can only be used in an index.
|
// dataObject is not null, as this mapper can only be used in an index.
|
||||||
return AccessController.doPrivileged(
|
return getValueFromObject(
|
||||||
new PrivilegedAction<Object>() {
|
propertyName,
|
||||||
@Override
|
accessType,
|
||||||
public Object run() {
|
dataObject,
|
||||||
final Getter getter = ReflectionTools.getGetter(
|
entityInstantiator.getEnversService().getServiceRegistry()
|
||||||
dataObject.getClass(),
|
|
||||||
propertyName,
|
|
||||||
accessType,
|
|
||||||
entityInstantiator.getEnversService().getServiceRegistry()
|
|
||||||
);
|
|
||||||
return getter.get( dataObject );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
/**
|
/**
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public final class MiddleRelatedComponentMapper implements MiddleComponentMapper {
|
public final class MiddleRelatedComponentMapper extends AbstractMiddleComponentMapper {
|
||||||
private final MiddleIdData relatedIdData;
|
private final MiddleIdData relatedIdData;
|
||||||
|
|
||||||
public MiddleRelatedComponentMapper(MiddleIdData relatedIdData) {
|
public MiddleRelatedComponentMapper(MiddleIdData relatedIdData) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
* @author Chris Cranford
|
* @author Chris Cranford
|
||||||
*/
|
*/
|
||||||
public final class MiddleSimpleComponentMapper implements MiddleComponentMapper {
|
public final class MiddleSimpleComponentMapper extends AbstractMiddleComponentMapper {
|
||||||
private final Configuration configuration;
|
private final Configuration configuration;
|
||||||
private final String propertyName;
|
private final String propertyName;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ import org.hibernate.envers.internal.tools.query.Parameters;
|
||||||
*
|
*
|
||||||
* @author Adam Warski (adam at warski dot org)
|
* @author Adam Warski (adam at warski dot org)
|
||||||
*/
|
*/
|
||||||
public final class MiddleStraightComponentMapper implements MiddleComponentMapper {
|
public final class MiddleStraightComponentMapper extends AbstractMiddleComponentMapper {
|
||||||
private final String propertyName;
|
private final String propertyName;
|
||||||
|
|
||||||
public MiddleStraightComponentMapper(String propertyName) {
|
public MiddleStraightComponentMapper(String propertyName) {
|
||||||
|
|
|
@ -6,13 +6,20 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor;
|
package org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
|
import org.hibernate.envers.exception.AuditException;
|
||||||
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
import org.hibernate.envers.internal.entities.EntityInstantiator;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
|
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
|
||||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a persistent collection.
|
* Initializes a persistent collection.
|
||||||
|
@ -58,4 +65,43 @@ public abstract class AbstractCollectionInitializor<T> implements Initializor<T>
|
||||||
|
|
||||||
return collection;
|
return collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform an action in a privileged block.
|
||||||
|
*
|
||||||
|
* @param block the lambda to executed in privileged.
|
||||||
|
* @param <R> the return type
|
||||||
|
* @return the result of the privileged call, may be {@literal null}
|
||||||
|
*/
|
||||||
|
protected <R> R doPrivileged(Supplier<R> block) {
|
||||||
|
if ( System.getSecurityManager() != null ) {
|
||||||
|
return AccessController.doPrivileged( (PrivilegedAction<R>) block::get );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return block.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new object based on the specified class with the given constructor arguments.
|
||||||
|
*
|
||||||
|
* @param clazz the class, must not be {@literal null}
|
||||||
|
* @param args the variadic constructor arguments, may be omitted.
|
||||||
|
* @param <R> the return class type
|
||||||
|
* @return a new instance of the class
|
||||||
|
*/
|
||||||
|
protected <R> R newObjectInstance(Class<R> clazz, Object... args) {
|
||||||
|
return doPrivileged( () -> {
|
||||||
|
try {
|
||||||
|
final Constructor<R> constructor = ReflectHelper.getDefaultConstructor( clazz );
|
||||||
|
if ( constructor == null ) {
|
||||||
|
throw new AuditException( "Failed to locate default constructor for class: " + clazz.getName() );
|
||||||
|
}
|
||||||
|
return constructor.newInstance( args );
|
||||||
|
}
|
||||||
|
catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,14 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor;
|
package org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.exception.AuditException;
|
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
|
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
|
||||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a non-indexed java collection (set or list, eventually sorted).
|
* Initializes a non-indexed java collection (set or list, eventually sorted).
|
||||||
|
@ -45,25 +40,7 @@ public class BasicCollectionInitializor<T extends Collection> extends AbstractCo
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected T initializeCollection(int size) {
|
protected T initializeCollection(int size) {
|
||||||
return AccessController.doPrivileged(
|
return newObjectInstance( collectionClass );
|
||||||
new PrivilegedAction<T>() {
|
|
||||||
@Override
|
|
||||||
public T run() {
|
|
||||||
try {
|
|
||||||
return (T) ReflectHelper.getDefaultConstructor( collectionClass ).newInstance();
|
|
||||||
}
|
|
||||||
catch (InstantiationException e) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException e) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
catch (InvocationTargetException e) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,18 +6,13 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor;
|
package org.hibernate.envers.internal.entities.mapper.relation.lazy.initializor;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.security.AccessController;
|
|
||||||
import java.security.PrivilegedAction;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.envers.boot.internal.EnversService;
|
import org.hibernate.envers.boot.internal.EnversService;
|
||||||
import org.hibernate.envers.exception.AuditException;
|
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
import org.hibernate.envers.internal.entities.mapper.relation.MiddleComponentData;
|
||||||
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
|
import org.hibernate.envers.internal.entities.mapper.relation.query.RelationQueryGenerator;
|
||||||
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a map.
|
* Initializes a map.
|
||||||
|
@ -47,25 +42,7 @@ public class MapCollectionInitializor<T extends Map> extends AbstractCollectionI
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected T initializeCollection(int size) {
|
protected T initializeCollection(int size) {
|
||||||
return AccessController.doPrivileged(
|
return newObjectInstance( collectionClass );
|
||||||
new PrivilegedAction<T>() {
|
|
||||||
@Override
|
|
||||||
public T run() {
|
|
||||||
try {
|
|
||||||
return (T) ReflectHelper.getDefaultConstructor( collectionClass ).newInstance();
|
|
||||||
}
|
|
||||||
catch (InstantiationException e) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException e) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
catch (InvocationTargetException e) {
|
|
||||||
throw new AuditException( e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -51,21 +51,23 @@ public class SortedMapCollectionInitializor extends MapCollectionInitializor<Sor
|
||||||
if ( comparator == null ) {
|
if ( comparator == null ) {
|
||||||
return super.initializeCollection( size );
|
return super.initializeCollection( size );
|
||||||
}
|
}
|
||||||
try {
|
return doPrivileged( () -> {
|
||||||
return collectionClass.getConstructor( Comparator.class ).newInstance( comparator );
|
try {
|
||||||
}
|
return collectionClass.getConstructor( Comparator.class ).newInstance( comparator );
|
||||||
catch (InstantiationException e) {
|
}
|
||||||
throw new AuditException( e );
|
catch (InstantiationException e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
catch (IllegalAccessException e) {
|
}
|
||||||
throw new AuditException( e );
|
catch (IllegalAccessException e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
catch (NoSuchMethodException e) {
|
}
|
||||||
throw new AuditException( e );
|
catch (NoSuchMethodException e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
catch (InvocationTargetException e) {
|
}
|
||||||
throw new AuditException( e );
|
catch (InvocationTargetException e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,20 +52,22 @@ public class SortedSetCollectionInitializor extends BasicCollectionInitializor<S
|
||||||
if ( comparator == null ) {
|
if ( comparator == null ) {
|
||||||
return super.initializeCollection( size );
|
return super.initializeCollection( size );
|
||||||
}
|
}
|
||||||
try {
|
return doPrivileged( () -> {
|
||||||
return collectionClass.getConstructor( Comparator.class ).newInstance( comparator );
|
try {
|
||||||
}
|
return collectionClass.getConstructor( Comparator.class ).newInstance(comparator);
|
||||||
catch (InstantiationException e) {
|
}
|
||||||
throw new AuditException( e );
|
catch (InstantiationException e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
catch (IllegalAccessException e) {
|
}
|
||||||
throw new AuditException( e );
|
catch (IllegalAccessException e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
catch (NoSuchMethodException e) {
|
}
|
||||||
throw new AuditException( e );
|
catch (NoSuchMethodException e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
catch (InvocationTargetException e) {
|
}
|
||||||
throw new AuditException( e );
|
catch (InvocationTargetException e) {
|
||||||
}
|
throw new AuditException( e );
|
||||||
|
}
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue