DATAMONGO-1012 - Identifier initialization for lazy DBRef proxies with field access.
We now initialize the ID property for proxies created for lazily initialized DBRefs. This will allow the lookup of ID properties for types that use field access without initializing the entire proxy.
This commit is contained in:
committed by
Oliver Gierke
parent
6fe7f220f9
commit
6f06ccec8e
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface DbRefProxyHandler {
|
||||
|
||||
Object populateId(MongoPersistentProperty property, DBRef source, Object proxy);
|
||||
}
|
||||
@@ -39,7 +39,8 @@ public interface DbRefResolver {
|
||||
* @param callback will never be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback);
|
||||
Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||
DbRefProxyHandler proxyHandler);
|
||||
|
||||
/**
|
||||
* Creates a {@link DBRef} instance for the given {@link org.springframework.data.mongodb.core.mapping.DBRef}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.mapping.model.DefaultSpELExpressionEvaluator;
|
||||
import org.springframework.data.mapping.model.SpELContext;
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.DBRef;
|
||||
|
||||
/**
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class DefaultDbRefProxyHandler implements DbRefProxyHandler {
|
||||
|
||||
private final SpELContext spELContext;
|
||||
private final MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||
private final ValueResolver resolver;
|
||||
|
||||
/**
|
||||
* @param spELContext must not be {@literal null}.
|
||||
* @param conversionService must not be {@literal null}.
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
public DefaultDbRefProxyHandler(SpELContext spELContext,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext, ValueResolver resolver) {
|
||||
|
||||
this.spELContext = spELContext;
|
||||
this.mappingContext = mappingContext;
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.DbRefProxyHandler#populateId(com.mongodb.DBRef, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Object populateId(MongoPersistentProperty property, DBRef source, Object proxy) {
|
||||
|
||||
if (source == null) {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
MongoPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(property);
|
||||
MongoPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
|
||||
if (idProperty.usePropertyAccess()) {
|
||||
return proxy;
|
||||
}
|
||||
|
||||
SpELExpressionEvaluator evaluator = new DefaultSpELExpressionEvaluator(proxy, spELContext);
|
||||
BeanWrapper<Object> proxyWrapper = BeanWrapper.create(proxy, null);
|
||||
|
||||
DBObject object = new BasicDBObject(idProperty.getFieldName(), source.getId());
|
||||
ObjectPath objectPath = ObjectPath.ROOT.push(proxy, persistentEntity, null);
|
||||
proxyWrapper.setProperty(idProperty, resolver.getValueInternal(idProperty, object, evaluator, objectPath));
|
||||
|
||||
return proxy;
|
||||
}
|
||||
}
|
||||
@@ -77,13 +77,14 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
* @see org.springframework.data.mongodb.core.convert.DbRefResolver#resolveDbRef(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, org.springframework.data.mongodb.core.convert.DbRefResolverCallback)
|
||||
*/
|
||||
@Override
|
||||
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) {
|
||||
public Object resolveDbRef(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||
DbRefProxyHandler handler) {
|
||||
|
||||
Assert.notNull(property, "Property must not be null!");
|
||||
Assert.notNull(callback, "Callback must not be null!");
|
||||
|
||||
if (isLazyDbRef(property)) {
|
||||
return createLazyLoadingProxy(property, dbref, callback);
|
||||
return createLazyLoadingProxy(property, dbref, callback, handler);
|
||||
}
|
||||
|
||||
return callback.resolve(property);
|
||||
@@ -112,7 +113,8 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
* @param callback must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private Object createLazyLoadingProxy(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback) {
|
||||
private Object createLazyLoadingProxy(MongoPersistentProperty property, DBRef dbref, DbRefResolverCallback callback,
|
||||
DbRefProxyHandler handler) {
|
||||
|
||||
Class<?> propertyType = property.getType();
|
||||
LazyLoadingInterceptor interceptor = new LazyLoadingInterceptor(property, dbref, exceptionTranslator, callback);
|
||||
@@ -122,7 +124,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
Factory factory = (Factory) objenesis.newInstance(getEnhancedTypeFor(propertyType));
|
||||
factory.setCallbacks(new Callback[] { interceptor });
|
||||
|
||||
return factory;
|
||||
return handler.populateId(property, dbref, factory);
|
||||
}
|
||||
|
||||
ProxyFactory proxyFactory = new ProxyFactory();
|
||||
@@ -135,7 +137,7 @@ public class DefaultDbRefResolver implements DbRefResolver {
|
||||
proxyFactory.addInterface(propertyType);
|
||||
proxyFactory.addAdvice(interceptor);
|
||||
|
||||
return proxyFactory.getProxy();
|
||||
return handler.populateId(property, dbref, proxyFactory.getProxy());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link DbRefResolverCallback}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class DefaultDbRefResolverCallback implements DbRefResolverCallback {
|
||||
|
||||
private final DBObject surroundingObject;
|
||||
private final ObjectPath path;
|
||||
private final ValueResolver resolver;
|
||||
private final SpELExpressionEvaluator evaluator;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultDbRefResolverCallback} using the given {@link DBObject}, {@link ObjectPath},
|
||||
* {@link ValueResolver} and {@link SpELExpressionEvaluator}.
|
||||
*
|
||||
* @param surroundingObject must not be {@literal null}.
|
||||
* @param path must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @param resolver must not be {@literal null}.
|
||||
*/
|
||||
public DefaultDbRefResolverCallback(DBObject surroundingObject, ObjectPath path, SpELExpressionEvaluator evaluator,
|
||||
ValueResolver resolver) {
|
||||
|
||||
this.surroundingObject = surroundingObject;
|
||||
this.path = path;
|
||||
this.resolver = resolver;
|
||||
this.evaluator = evaluator;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.DbRefResolverCallback#resolve(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty)
|
||||
*/
|
||||
@Override
|
||||
public Object resolve(MongoPersistentProperty property) {
|
||||
return resolver.getValueInternal(property, surroundingObject, evaluator, path);
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.convert.ConversionException;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.ConversionServiceFactory;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.convert.CollectionFactory;
|
||||
import org.springframework.data.convert.EntityInstantiator;
|
||||
import org.springframework.data.convert.TypeMapper;
|
||||
@@ -74,7 +74,7 @@ import com.mongodb.DBRef;
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware {
|
||||
public class MappingMongoConverter extends AbstractMongoConverter implements ApplicationContextAware, ValueResolver {
|
||||
|
||||
protected static final Logger LOGGER = LoggerFactory.getLogger(MappingMongoConverter.class);
|
||||
|
||||
@@ -82,6 +82,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
protected final SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
|
||||
protected final QueryMapper idMapper;
|
||||
protected final DbRefResolver dbRefResolver;
|
||||
|
||||
protected ApplicationContext applicationContext;
|
||||
protected MongoTypeMapper typeMapper;
|
||||
protected String mapKeyDotReplacement = null;
|
||||
@@ -94,11 +95,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* @param mongoDbFactory must not be {@literal null}.
|
||||
* @param mappingContext must not be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public MappingMongoConverter(DbRefResolver dbRefResolver,
|
||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
||||
|
||||
super(ConversionServiceFactory.createDefaultConversionService());
|
||||
super(new DefaultConversionService());
|
||||
|
||||
Assert.notNull(dbRefResolver, "DbRefResolver must not be null!");
|
||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||
@@ -277,7 +277,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
entity.doWithAssociations(new AssociationHandler<MongoPersistentProperty>() {
|
||||
public void doWithAssociation(Association<MongoPersistentProperty> association) {
|
||||
|
||||
MongoPersistentProperty property = association.getInverse();
|
||||
final MongoPersistentProperty property = association.getInverse();
|
||||
Object value = dbo.get(property.getName());
|
||||
|
||||
if (value == null) {
|
||||
@@ -285,13 +285,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
}
|
||||
|
||||
DBRef dbref = value instanceof DBRef ? (DBRef) value : null;
|
||||
wrapper.setProperty(property, dbRefResolver.resolveDbRef(property, dbref, new DbRefResolverCallback() {
|
||||
|
||||
@Override
|
||||
public Object resolve(MongoPersistentProperty property) {
|
||||
return getValueInternal(property, dbo, evaluator, currentPath);
|
||||
}
|
||||
}));
|
||||
DbRefProxyHandler handler = new DefaultDbRefProxyHandler(spELContext, mappingContext,
|
||||
MappingMongoConverter.this);
|
||||
DbRefResolverCallback callback = new DefaultDbRefResolverCallback(dbo, currentPath, evaluator,
|
||||
MappingMongoConverter.this);
|
||||
|
||||
wrapper.setProperty(property, dbRefResolver.resolveDbRef(property, dbref, callback, handler));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -813,9 +813,13 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
idMapper.convertId(id));
|
||||
}
|
||||
|
||||
protected Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator evaluator,
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mongodb.core.convert.ValueResolver#getValueInternal(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty, com.mongodb.DBObject, org.springframework.data.mapping.model.SpELExpressionEvaluator, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator evaluator,
|
||||
ObjectPath path) {
|
||||
|
||||
return new MongoDbPropertyValueProvider(dbo, evaluator, path).getPropertyValue(prop);
|
||||
}
|
||||
|
||||
@@ -1036,11 +1040,11 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
|
||||
/**
|
||||
* Creates a new {@link MongoDbPropertyValueProvider} for the given source, {@link SpELExpressionEvaluator} and
|
||||
* parent object.
|
||||
* {@link ObjectPath}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param evaluator must not be {@literal null}.
|
||||
* @param parent can be {@literal null}.
|
||||
* @param path can be {@literal null}.
|
||||
*/
|
||||
public MongoDbPropertyValueProvider(DBObject source, SpELExpressionEvaluator evaluator, ObjectPath path) {
|
||||
|
||||
@@ -1078,7 +1082,7 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
private class ConverterAwareSpELExpressionParameterValueProvider extends
|
||||
SpELExpressionParameterValueProvider<MongoPersistentProperty> {
|
||||
|
||||
private final ObjectPath parent;
|
||||
private final ObjectPath path;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ConverterAwareSpELExpressionParameterValueProvider}.
|
||||
@@ -1088,10 +1092,10 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
* @param delegate must not be {@literal null}.
|
||||
*/
|
||||
public ConverterAwareSpELExpressionParameterValueProvider(SpELExpressionEvaluator evaluator,
|
||||
ConversionService conversionService, ParameterValueProvider<MongoPersistentProperty> delegate, ObjectPath parent) {
|
||||
ConversionService conversionService, ParameterValueProvider<MongoPersistentProperty> delegate, ObjectPath path) {
|
||||
|
||||
super(evaluator, conversionService, delegate);
|
||||
this.parent = parent;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1100,23 +1104,23 @@ public class MappingMongoConverter extends AbstractMongoConverter implements App
|
||||
*/
|
||||
@Override
|
||||
protected <T> T potentiallyConvertSpelValue(Object object, Parameter<T, MongoPersistentProperty> parameter) {
|
||||
return readValue(object, parameter.getType(), parent);
|
||||
return readValue(object, parameter.getType(), path);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T readValue(Object value, TypeInformation<?> type, ObjectPath parent) {
|
||||
private <T> T readValue(Object value, TypeInformation<?> type, ObjectPath path) {
|
||||
|
||||
Class<?> rawType = type.getType();
|
||||
|
||||
if (conversions.hasCustomReadTarget(value.getClass(), rawType)) {
|
||||
return (T) conversionService.convert(value, rawType);
|
||||
} else if (value instanceof DBRef) {
|
||||
return potentiallyReadOrResolveDbRef((DBRef) value, type, parent, rawType);
|
||||
return potentiallyReadOrResolveDbRef((DBRef) value, type, path, rawType);
|
||||
} else if (value instanceof BasicDBList) {
|
||||
return (T) readCollectionOrArray(type, (BasicDBList) value, parent);
|
||||
return (T) readCollectionOrArray(type, (BasicDBList) value, path);
|
||||
} else if (value instanceof DBObject) {
|
||||
return (T) read(type, (DBObject) value, parent);
|
||||
return (T) read(type, (DBObject) value, path);
|
||||
} else {
|
||||
return (T) getPotentiallyConvertedSimpleRead(value, rawType);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.mongodb.core.convert;
|
||||
|
||||
import org.springframework.data.mapping.model.SpELExpressionEvaluator;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
|
||||
/**
|
||||
* Internal API to trigger the resolution of properties.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
interface ValueResolver {
|
||||
|
||||
/**
|
||||
* Resolves the value for the given {@link MongoPersistentProperty} within the given {@link DBObject} using the given
|
||||
* {@link SpELExpressionEvaluator} and {@link ObjectPath}.
|
||||
*
|
||||
* @param prop
|
||||
* @param dbo
|
||||
* @param evaluator
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
Object getValueInternal(MongoPersistentProperty prop, DBObject dbo, SpELExpressionEvaluator evaluator,
|
||||
ObjectPath parent);
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -38,10 +39,12 @@ import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.PersistenceConstructor;
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
import org.springframework.data.mapping.model.BeanWrapper;
|
||||
import org.springframework.data.mongodb.MongoDbFactory;
|
||||
import org.springframework.data.mongodb.core.MongoExceptionTranslator;
|
||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverterUnitTests.Person;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||
import org.springframework.util.SerializationUtils;
|
||||
|
||||
@@ -491,6 +494,24 @@ public class DbRefMappingMongoConverterUnitTests {
|
||||
assertThat(found.nested.reference, is(found));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testname() {
|
||||
|
||||
MongoPersistentEntity<?> entity = mappingContext.getPersistentEntity(ClassWithLazyDbRefs.class);
|
||||
MongoPersistentProperty property = entity.getPersistentProperty("dbRefToConcreteType");
|
||||
|
||||
Object dbRef = converter.toDBRef(new LazyDbRefTarget(new ObjectId().toString()), property);
|
||||
|
||||
DBObject object = new BasicDBObject("dbRefToConcreteType", dbRef);
|
||||
|
||||
ClassWithLazyDbRefs result = converter.read(ClassWithLazyDbRefs.class, object);
|
||||
|
||||
BeanWrapper<LazyDbRefTarget> wrapper = BeanWrapper.create(result.dbRefToConcreteType, null);
|
||||
MongoPersistentProperty idProperty = mappingContext.getPersistentEntity(LazyDbRefTarget.class).getIdProperty();
|
||||
|
||||
assertThat(wrapper.getProperty(idProperty), is(notNullValue()));
|
||||
}
|
||||
|
||||
private Object transport(Object result) {
|
||||
return SerializationUtils.deserialize(SerializationUtils.serialize(result));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user