SGF-595 - Integrate Spring Data Commons Java 8 support.

This commit is contained in:
John Blum
2017-02-21 09:49:27 -08:00
committed by Mark Paluch
parent 7d91c8ed3a
commit d108553870
40 changed files with 877 additions and 557 deletions

View File

@@ -310,11 +310,8 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation
queryString, result));
}
}
catch (IndexInvalidException ex) {
throw convertGemFireQueryException(ex);
}
catch (QueryInvalidException ex) {
throw convertGemFireQueryException(ex);
catch (IndexInvalidException | QueryInvalidException e) {
throw convertGemFireQueryException(e);
}
catch (GemFireCheckedException e) {
throw convertGemFireAccessException(e);
@@ -322,14 +319,14 @@ public class GemfireTemplate extends GemfireAccessor implements GemfireOperation
catch (GemFireException e) {
throw convertGemFireAccessException(e);
}
catch (RuntimeException ex) {
catch (RuntimeException e) {
// test for CqInvalidException (removed in 6.5)
if (GemfireCacheUtils.isCqInvalidException(ex)) {
throw GemfireCacheUtils.convertCqInvalidException(ex);
if (GemfireCacheUtils.isCqInvalidException(e)) {
throw GemfireCacheUtils.convertCqInvalidException(e);
}
// callback code threw application exception
throw ex;
throw e;
}
}

View File

@@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
@@ -63,6 +64,7 @@ import org.springframework.data.gemfire.config.annotation.support.GemFireCompone
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.data.gemfire.mapping.GemfirePersistentProperty;
import org.springframework.data.gemfire.mapping.annotation.ClientRegion;
import org.springframework.data.gemfire.mapping.annotation.LocalRegion;
import org.springframework.data.gemfire.mapping.annotation.PartitionRegion;
@@ -218,7 +220,9 @@ public class EntityDefinedRegionsConfiguration
/* (non-Javadoc) */
protected GemfirePersistentEntity<?> getPersistentEntity(Class<?> persistentEntityType) {
return resolveMappingContext().getPersistentEntity(persistentEntityType);
return resolveMappingContext().getPersistentEntity(persistentEntityType).orElseThrow(
() -> new IllegalStateException(String.format("PersistentEntity for type [%s] not found",
persistentEntityType)));
}
/* (non-Javadoc) */
@@ -475,13 +479,15 @@ public class EntityDefinedRegionsConfiguration
/* (non-Javadoc) */
protected Class<?> resolveDomainType(GemfirePersistentEntity persistentEntity) {
return defaultIfNull(persistentEntity.getType(), Object.class);
return Optional.of(persistentEntity.getType()).orElse(Object.class);
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected Class<?> resolveIdType(GemfirePersistentEntity persistentEntity) {
return (persistentEntity.hasIdProperty() ?
defaultIfNull(persistentEntity.getIdProperty().getActualType(), Object.class) : Object.class);
return (Class<?>) persistentEntity.getIdProperty()
.map((idProperty) -> ((GemfirePersistentProperty) idProperty).getActualType())
.orElse(Object.class);
}
/* (non-Javadoc) */

View File

@@ -18,6 +18,7 @@
package org.springframework.data.gemfire.config.annotation;
import java.lang.annotation.Annotation;
import java.util.Optional;
import org.apache.geode.cache.Region;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -110,26 +111,20 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
super.postProcess(importingClassMetadata, registry, persistentEntity);
if (isAnnotationPresent(importingClassMetadata, getEnableIndexesAnnotationTypeName())) {
final AnnotationAttributes enableIndexesAttributes =
AnnotationAttributes enableIndexesAttributes =
getAnnotationAttributes(importingClassMetadata, getEnableIndexesAnnotationTypeName());
localPersistentEntity.doWithProperties(new PropertyHandler<GemfirePersistentProperty>() {
@Override
public void doWithPersistentProperty(GemfirePersistentProperty persistentProperty) {
Id idAnnotation = persistentProperty.findAnnotation(Id.class);
localPersistentEntity.doWithProperties((PropertyHandler<GemfirePersistentProperty>) persistentProperty -> {
Optional<Id> idAnnotation = persistentProperty.findAnnotation(Id.class);
if (idAnnotation != null) {
registerIndexBeanDefinition(enableIndexesAttributes, localPersistentEntity, persistentProperty,
IndexType.KEY, idAnnotation, registry);
}
idAnnotation.ifPresent(id -> registerIndexBeanDefinition(enableIndexesAttributes, localPersistentEntity,
persistentProperty, IndexType.KEY, id, registry));
Indexed indexedAnnotation = persistentProperty.findAnnotation(Indexed.class);
Optional<Indexed> indexedAnnotation = persistentProperty.findAnnotation(Indexed.class);
if (indexedAnnotation != null) {
registerIndexBeanDefinition(enableIndexesAttributes, localPersistentEntity, persistentProperty,
indexedAnnotation.type(), indexedAnnotation, registry);
}
}
indexedAnnotation.ifPresent(
indexed -> registerIndexBeanDefinition(enableIndexesAttributes, localPersistentEntity,
persistentProperty, indexed.type(), indexed, registry));
});
}

View File

@@ -21,6 +21,8 @@ import java.lang.reflect.Field;
import org.springframework.data.gemfire.mapping.model.GemfireSimpleTypeHolder;
import org.springframework.data.mapping.context.AbstractMappingContext;
import org.springframework.data.mapping.model.MutablePersistentEntity;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
@@ -57,9 +59,19 @@ public class GemfireMappingContext extends AbstractMappingContext<GemfirePersist
/**
* @inheritDoc
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.model.MutablePersistentEntity, org.springframework.data.mapping.model.SimpleTypeHolder)
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentProperty(Property, MutablePersistentEntity, SimpleTypeHolder)
*/
@Override
protected GemfirePersistentProperty createPersistentProperty(Property property, GemfirePersistentEntity<?> owner,
SimpleTypeHolder simpleTypeHolder) {
return new GemfirePersistentProperty(property, owner, simpleTypeHolder);
}
/**
* @deprecated use {@link #createPersistentProperty(Property, GemfirePersistentEntity, SimpleTypeHolder)} instead
*/
@Deprecated
protected GemfirePersistentProperty createPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
GemfirePersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {

View File

@@ -19,6 +19,7 @@ package org.springframework.data.gemfire.mapping;
import static org.springframework.data.gemfire.util.SpringUtils.defaultIfEmpty;
import java.lang.annotation.Annotation;
import java.util.Optional;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
@@ -49,7 +50,6 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
/* (non-Javadoc) */
protected static Annotation resolveRegionAnnotation(Class<?> persistentEntityType) {
for (Class<? extends Annotation> regionAnnotationType : Region.REGION_ANNOTATION_TYPES) {
Annotation regionAnnotation = AnnotatedElementUtils.getMergedAnnotation(
persistentEntityType, regionAnnotationType);
@@ -64,9 +64,9 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
/* (non-Javadoc) */
protected static String resolveRegionName(Class<?> persistentEntityType, Annotation regionAnnotation) {
String regionName = (regionAnnotation != null
? getAnnotationAttributeStringValue(regionAnnotation, "value") : null);
String regionName = Optional.ofNullable(regionAnnotation)
.map((annotation) -> getAnnotationAttributeStringValue(annotation, "value"))
.orElse(null);
return defaultIfEmpty(regionName, persistentEntityType.getSimpleName());
}
@@ -123,8 +123,9 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
* @see #getRegionAnnotation()
*/
public Class<? extends Annotation> getRegionAnnotationType() {
Annotation regionAnnotation = getRegionAnnotation();
return (regionAnnotation != null ? regionAnnotation.annotationType() : null);
return Optional.ofNullable(getRegionAnnotation())
.map((annotation) -> ((Annotation) annotation).annotationType())
.orElse(null);
}
/**
@@ -148,15 +149,17 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
GemfirePersistentProperty property) {
if (property.isIdProperty()) {
if (hasIdProperty()) {
GemfirePersistentProperty currentIdProperty = getIdProperty();
Optional<GemfirePersistentProperty> optionalIdProperty = getIdProperty();
if (currentIdProperty.isExplicitIdProperty()) {
if (optionalIdProperty.isPresent()) {
GemfirePersistentProperty idProperty = getIdProperty().get();
if (idProperty.isExplicitIdProperty()) {
if (property.isExplicitIdProperty()) {
throw new MappingException(String.format(
"Attempt to add explicit id property [%1$s] but already have id property [%2$s] registered as explicit;"
+ " Please check your object [%3$s] mapping configuration",
property.getName(), currentIdProperty.getName(), getType().getName()));
property.getName(), idProperty.getName(), getType().getName()));
}
return null;

View File

@@ -20,6 +20,7 @@ import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.Optional;
import java.util.Set;
import org.springframework.data.annotation.Id;
@@ -28,6 +29,7 @@ import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
/**
@@ -39,6 +41,13 @@ public class GemfirePersistentProperty extends AnnotationBasedPersistentProperty
protected static final Set<String> SUPPORTED_IDENTIFIER_NAMES = asSet("id");
/* (non-Javadoc) */
private static Property newProperty(Field field, PropertyDescriptor propertyDescriptor) {
return Optional.ofNullable(field)
.map((theField) -> Property.of(theField, Optional.ofNullable(propertyDescriptor)))
.orElseGet(() -> Property.of(propertyDescriptor));
}
/* (non-Javadoc) */
private static SimpleTypeHolder resolveSimpleTypeHolder(SimpleTypeHolder source) {
return (source instanceof GemfireSimpleTypeHolder ? source
@@ -46,22 +55,45 @@ public class GemfirePersistentProperty extends AnnotationBasedPersistentProperty
}
/**
* Constructs an instance of the {@link GemfirePersistentProperty} initialized with entity
* persistent property information (meta-data).
* Constructs an instance of {@link GemfirePersistentProperty} initialized with entity persistent property
* information (meta-data).
*
* @param field entity {@link Field} corresponding to the persistent property.
* @param propertyDescriptor {@link PropertyDescriptor} for the entity's persistent property.
* @param owner entity owning the persistent property.
* @param field {@link GemfirePersistentEntity entity} {@link Field} for the persistent property.
* @param propertyDescriptor {@link PropertyDescriptor} for the {@link GemfirePersistentEntity entity's}
* persistent property.
* @param owner {@link GemfirePersistentEntity entity} owning the persistent property.
* @param simpleTypeHolder {@link SimpleTypeHolder} used to handle primitive types.
* @see org.springframework.data.mapping.model.SimpleTypeHolder
* @see #GemfirePersistentProperty(Property, PersistentEntity, SimpleTypeHolder)
* @see #newProperty(Field, PropertyDescriptor)
* @see org.springframework.data.mapping.PersistentEntity
* @see org.springframework.data.mapping.PersistentProperty
* @see org.springframework.data.mapping.model.SimpleTypeHolder
* @see java.beans.PropertyDescriptor
* @see java.lang.reflect.Field
*/
public GemfirePersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
PersistentEntity<?, GemfirePersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, resolveSimpleTypeHolder(simpleTypeHolder));
this(newProperty(field, propertyDescriptor), owner, resolveSimpleTypeHolder(simpleTypeHolder));
}
/**
* Constructs an instance of {@link GemfirePersistentProperty} initialized with entity persistent property
* information (meta-data).
*
* @param property {@link Property} representing the {@link GemfirePersistentEntity entity's} persistent property.
* @param owner {@link GemfirePersistentEntity entity} owning the persistent property.
* @param simpleTypeHolder {@link SimpleTypeHolder} used to handle primitive types.
* @see org.springframework.data.mapping.PersistentEntity
* @see org.springframework.data.mapping.PersistentProperty
* @see org.springframework.data.mapping.model.Property
* @see org.springframework.data.mapping.model.SimpleTypeHolder
* @see AnnotationBasedPersistentProperty(Property, PersistentEntity, SimpleTypeHolder)
*/
public GemfirePersistentProperty(Property property, PersistentEntity<?, GemfirePersistentProperty> owner,
SimpleTypeHolder simpleTypeHolder) {
super(property, owner, simpleTypeHolder);
}
/**
@@ -99,6 +131,6 @@ public class GemfirePersistentProperty extends AnnotationBasedPersistentProperty
*/
@Override
public boolean usePropertyAccess() {
return (super.usePropertyAccess() || (getField() == null && this.propertyDescriptor != null));
return (super.usePropertyAccess() || !getProperty().isFieldBacked());
}
}

View File

@@ -13,17 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.mapping;
import java.util.Optional;
import org.apache.geode.pdx.PdxReader;
import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.util.Assert;
/**
* {@link PropertyValueProvider} to read property values from a {@link PdxReader}.
* {@link PropertyValueProvider} to read property values from {@link PdxReader}.
*
* @author Oliver Gierke
* @author David Turanski
* @author John Blum
*/
class GemfirePropertyValueProvider implements PropertyValueProvider<GemfirePersistentProperty> {
@@ -35,7 +39,7 @@ class GemfirePropertyValueProvider implements PropertyValueProvider<GemfirePersi
* @param reader must not be {@literal null}.
*/
public GemfirePropertyValueProvider(PdxReader reader) {
Assert.notNull(reader);
Assert.notNull(reader, "PdxReader must not be null");
this.reader = reader;
}
@@ -45,7 +49,7 @@ class GemfirePropertyValueProvider implements PropertyValueProvider<GemfirePersi
*/
@Override
@SuppressWarnings("unchecked")
public <T> T getPropertyValue(GemfirePersistentProperty property) {
return (T) reader.readField(property.getName());
public <T> Optional<T> getPropertyValue(GemfirePersistentProperty property) {
return Optional.ofNullable((T) reader.readField(property.getName()));
}
}

View File

@@ -15,8 +15,11 @@
*/
package org.springframework.data.gemfire.mapping;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -115,8 +118,8 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
*/
public MappingPdxSerializer(GemfireMappingContext mappingContext, ConversionService conversionService) {
Assert.notNull(mappingContext);
Assert.notNull(conversionService);
Assert.notNull(mappingContext, "GemfireMappingContext must not be null");
Assert.notNull(conversionService, "ConversionService must not be null");
this.mappingContext = mappingContext;
this.conversionService = conversionService;
@@ -130,7 +133,7 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = new SpELContext(context, applicationContext);
this.context = new SpELContext(this.context, applicationContext);
}
/* (non-Javadoc) */
@@ -144,7 +147,7 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
* @param customSerializers a mapping of domain object class types and their corresponding PDX serializer.
*/
public void setCustomSerializers(Map<Class<?>, PdxSerializer> customSerializers) {
Assert.notNull(customSerializers);
Assert.notNull(customSerializers, "Custom PdxSerializers must not be null");
this.customSerializers = customSerializers;
}
@@ -159,7 +162,7 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
* @param gemfireInstantiators must not be {@literal null}.
*/
public void setGemfireInstantiators(Map<Class<?>, EntityInstantiator> gemfireInstantiators) {
Assert.notNull(gemfireInstantiators);
Assert.notNull(gemfireInstantiators, "EntityInstantiators must not be null");
this.instantiators = new EntityInstantiators(gemfireInstantiators);
}
@@ -177,46 +180,45 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
* {@inheritDoc}
*/
@Override
public Object fromData(final Class<?> type, final PdxReader reader) {
public Object fromData(Class<?> type, PdxReader reader) {
final GemfirePersistentEntity<?> entity = getPersistentEntity(type);
GemfirePersistentEntity<?> entity = getPersistentEntity(type);
final Object instance = getInstantiatorFor(entity).createInstance(entity,
new PersistentEntityParameterValueProvider<>(entity, new GemfirePropertyValueProvider(reader), null));
Object instance = getInstantiatorFor(entity).createInstance(entity,
new PersistentEntityParameterValueProvider<>(entity, new GemfirePropertyValueProvider(reader),
Optional.empty()));
final PersistentPropertyAccessor propertyAccessor =
PersistentPropertyAccessor propertyAccessor =
new ConvertingPropertyAccessor(entity.getPropertyAccessor(instance), getConversionService());
entity.doWithProperties(new PropertyHandler<GemfirePersistentProperty>() {
public void doWithPersistentProperty(GemfirePersistentProperty persistentProperty) {
if (!entity.isConstructorArgument(persistentProperty)) {
PdxSerializer customSerializer = getCustomSerializer(persistentProperty.getType());
entity.doWithProperties((PropertyHandler<GemfirePersistentProperty>) persistentProperty -> {
if (!entity.isConstructorArgument(persistentProperty)) {
PdxSerializer customSerializer = getCustomSerializer(persistentProperty.getType());
Object value = null;
Object value = null;
try {
if (log.isDebugEnabled()) {
log.debug(String.format("setting property [%1$s] for entity [%2$s] of type [%3$s] from PDX%4$s",
persistentProperty.getName(), instance, type, (customSerializer != null ?
String.format(" using custom PdxSerializer [%1$s]", customSerializer) : "")));
}
value = (customSerializer != null
? customSerializer.fromData(persistentProperty.getType(), reader)
: reader.readField(persistentProperty.getName()));
if (log.isDebugEnabled()) {
log.debug(String.format("with value [%1$s]", value));
}
propertyAccessor.setProperty(persistentProperty, value);
try {
if (log.isDebugEnabled()) {
log.debug(String.format("setting property [%1$s] for entity [%2$s] of type [%3$s] from PDX%4$s",
persistentProperty.getName(), instance, type, (customSerializer != null ?
String.format(" using custom PdxSerializer [%1$s]", customSerializer) : "")));
}
catch (Exception e) {
throw new MappingException(String.format(
"while setting value [%1$s] of property [%2$s] for entity of type [%3$s] from PDX%4$s",
value, persistentProperty.getName(), type, (customSerializer != null ?
String.format(" using custom PdxSerializer [%14s]", customSerializer) : "")), e);
value = (customSerializer != null
? customSerializer.fromData(persistentProperty.getType(), reader)
: reader.readField(persistentProperty.getName()));
if (log.isDebugEnabled()) {
log.debug(String.format("with value [%1$s]", value));
}
propertyAccessor.setProperty(persistentProperty, Optional.ofNullable(value));
}
catch (Exception e) {
throw new MappingException(String.format(
"While setting value [%1$s] of property [%2$s] for entity of type [%3$s] from PDX%4$s",
value, persistentProperty.getName(), type, (customSerializer != null ?
String.format(" using custom PdxSerializer [%14s]", customSerializer) : "")), e);
}
}
});
@@ -228,52 +230,51 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
* {@inheritDoc}
*/
@Override
public boolean toData(final Object value, final PdxWriter writer) {
@SuppressWarnings("unchecked")
public boolean toData(Object value, PdxWriter writer) {
GemfirePersistentEntity<?> entity = getPersistentEntity(value);
final PersistentPropertyAccessor propertyAccessor =
PersistentPropertyAccessor propertyAccessor =
new ConvertingPropertyAccessor(entity.getPropertyAccessor(value), getConversionService());
entity.doWithProperties(new PropertyHandler<GemfirePersistentProperty>() {
@Override @SuppressWarnings("unchecked")
public void doWithPersistentProperty(GemfirePersistentProperty persistentProperty) {
PdxSerializer customSerializer = getCustomSerializer(persistentProperty.getType());
entity.doWithProperties((PropertyHandler<GemfirePersistentProperty>) persistentProperty -> {
PdxSerializer customSerializer = getCustomSerializer(persistentProperty.getType());
Object propertyValue = null;
Optional<Object> propertyValue = null;
try {
propertyValue = propertyAccessor.getProperty(persistentProperty);
try {
propertyValue = propertyAccessor.getProperty(persistentProperty);
if (log.isDebugEnabled()) {
log.debug(String.format("Serializing entity property [%1$s] value [%2$s] of type [%3$s] to PDX%4$s",
persistentProperty.getName(), propertyValue, value.getClass(), (customSerializer != null ?
String.format(" using custom PdxSerializer [%s]", customSerializer) : "")));
}
if (customSerializer != null) {
customSerializer.toData(propertyValue, writer);
}
else {
writer.writeField(persistentProperty.getName(), propertyValue,
(Class<Object>) persistentProperty.getType());
}
if (log.isDebugEnabled()) {
log.debug(String.format("Serializing entity property [%1$s] value [%2$s] of type [%3$s] to PDX%4$s",
persistentProperty.getName(), propertyValue, value.getClass(), (customSerializer != null ?
String.format(" using custom PdxSerializer [%s]", customSerializer) : "")));
}
catch (Exception e) {
throw new MappingException(String.format(
"Error while serializing entity property [%1$s] value [%2$s] of type [%3$s] to PDX%4$s",
persistentProperty.getName(), propertyValue, value.getClass(),
(customSerializer != null ? String.format(" using custom PdxSerializer [%1$s].",
customSerializer.getClass().getName()) : ".")), e);
if (customSerializer != null) {
customSerializer.toData(propertyValue.orElse(null), writer);
}
else {
writer.writeField(persistentProperty.getName(), propertyValue.orElse(null),
(Class<Object>) persistentProperty.getType());
}
}
catch (Exception e) {
Object resolvedPropertyValue = (propertyValue != null ? propertyValue.orElse(null) : null);
throw new MappingException(String.format(
"While serializing entity property [%1$s] value [%2$s] of type [%3$s] to PDX%4$s",
persistentProperty.getName(), resolvedPropertyValue, value.getClass(),
(customSerializer != null ? String.format(" using custom PdxSerializer [%1$s].",
customSerializer.getClass().getName()) : ".")), e);
}
});
GemfirePersistentProperty idProperty = entity.getIdProperty();
Optional<GemfirePersistentProperty> idProperty = entity.getIdProperty();
if (idProperty != null) {
writer.markIdentityField(idProperty.getName());
}
idProperty.ifPresent(gemfirePersistentProperty ->
writer.markIdentityField(gemfirePersistentProperty.getName()));
return true;
}
@@ -325,6 +326,7 @@ public class MappingPdxSerializer implements PdxSerializer, ApplicationContextAw
* @see #getMappingContext()
*/
protected GemfirePersistentEntity<?> getPersistentEntity(Class<?> entityType) {
return getMappingContext().getPersistentEntity(entityType);
return getMappingContext().getPersistentEntity(entityType).orElseThrow(
() -> newIllegalArgumentException("Unable to resolve PersistentEntity for type [%]", entityType));
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.gemfire.mapping;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@@ -50,7 +52,7 @@ public class Regions implements Iterable<Region<?, ?>> {
Assert.notNull(regions, "Regions must not be null");
Assert.notNull(mappingContext, "MappingContext must not be null");
Map<String, Region<?, ?>> regionMap = new HashMap<String, Region<?, ?>>();
Map<String, Region<?, ?>> regionMap = new HashMap<>();
for (Region<?, ?> region : regions) {
regionMap.put(region.getName(), region);
@@ -72,12 +74,12 @@ public class Regions implements Iterable<Region<?, ?>> {
*/
@SuppressWarnings("unchecked")
public <T> Region<?, T> getRegion(Class<T> entityType) {
Assert.notNull(entityType, "entityType must not be null");
Assert.notNull(entityType, "Entity type must not be null");
GemfirePersistentEntity<?> entity = mappingContext.getPersistentEntity(entityType);
String regionName = (entity != null ? entity.getRegionName() : entityType.getSimpleName());
String regionName = this.mappingContext.getPersistentEntity(entityType).map((entity) -> entity.getRegionName())
.orElseGet(entityType::getSimpleName);
return (Region<?, T>) regions.get(regionName);
return (Region<?, T>) this.regions.get(regionName);
}
/**
@@ -92,7 +94,7 @@ public class Regions implements Iterable<Region<?, ?>> {
public <S, T> Region<S, T> getRegion(String namePath) {
Assert.hasText(namePath, "Region name/path is required");
return (Region<S, T>) regions.get(namePath);
return (Region<S, T>) this.regions.get(namePath);
}
/*
@@ -102,6 +104,6 @@ public class Regions implements Iterable<Region<?, ?>> {
*/
@Override
public Iterator<Region<?, ?>> iterator() {
return regions.values().iterator();
return this.regions.values().iterator();
}
}

View File

@@ -21,6 +21,7 @@ import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import javax.enterprise.context.spi.CreationalContext;
@@ -64,7 +65,7 @@ class GemfireRepositoryBean<T> extends CdiRepositoryBean<T> {
CustomRepositoryImplementationDetector detector, Bean<GemfireMappingContext> gemfireMappingContextBean,
Set<Bean<Region>> regionBeans) {
super(qualifiers, repositoryType, beanManager, detector);
super(qualifiers, repositoryType, beanManager, Optional.ofNullable(detector));
this.beanManager = beanManager;
this.gemfireMappingContextBean = gemfireMappingContextBean;
@@ -148,8 +149,12 @@ class GemfireRepositoryBean<T> extends CdiRepositoryBean<T> {
* @see #newGemfireRepositoryFactory()
*/
@Override
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType, Object customImplementation) {
return newGemfireRepositoryFactory().getRepository(repositoryType, customImplementation);
}
@SuppressWarnings("all")
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType,
Optional<Object> customImplementation) {
return (customImplementation.isPresent()
? newGemfireRepositoryFactory().getRepository(repositoryType, customImplementation.get())
: newGemfireRepositoryFactory().getRepository(repositoryType));
}
}

View File

@@ -32,7 +32,6 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
import org.springframework.data.repository.config.RepositoryConfigurationSource;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
import org.springframework.util.StringUtils;
/**
* {@link RepositoryConfigurationExtension} implementation handling GemFire specific extensions to the Repository XML
@@ -66,7 +65,7 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura
*/
@Override
protected Collection<Class<?>> getIdentifyingTypes() {
return Collections.<Class<?>>singleton(GemfireRepository.class);
return Collections.singleton(GemfireRepository.class);
}
/*
@@ -93,8 +92,9 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura
*/
@Override
public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource configurationSource) {
builder.addPropertyReference(MAPPING_CONTEXT_PROPERTY_NAME, resolveMappingContextBeanName(
configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME)));
builder.addPropertyReference(MAPPING_CONTEXT_PROPERTY_NAME,
configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME)
.orElse(DEFAULT_MAPPING_CONTEXT_BEAN_NAME));
}
/*
@@ -103,13 +103,9 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura
*/
@Override
public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource configurationSource) {
builder.addPropertyReference(MAPPING_CONTEXT_PROPERTY_NAME, resolveMappingContextBeanName(
configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME)));
}
/* (non-Javadoc) */
private static String resolveMappingContextBeanName(String source) {
return (StringUtils.hasText(source) ? source : DEFAULT_MAPPING_CONTEXT_BEAN_NAME);
builder.addPropertyReference(MAPPING_CONTEXT_PROPERTY_NAME,
configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME)
.orElse(DEFAULT_MAPPING_CONTEXT_BEAN_NAME));
}
/*
@@ -121,7 +117,7 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura
super.registerBeansForRoot(registry, configurationSource);
if (!StringUtils.hasText(configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME))) {
if (!configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME).isPresent()) {
registry.registerBeanDefinition(DEFAULT_MAPPING_CONTEXT_BEAN_NAME,
new RootBeanDefinition(GemfireMappingContext.class));
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.repository.query;
import java.util.Iterator;
@@ -98,7 +99,7 @@ class GemfireQueryCreator extends AbstractQueryCreator<QueryString, Predicates>
QueryString query = queryBuilder.create(criteria).orderBy(sort);
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Created Query '%1$s'", query.toString()));
LOG.debug(String.format("Created Query [%s]", query.toString()));
}
return query;

View File

@@ -43,29 +43,33 @@ import org.springframework.util.StringUtils;
*/
public class GemfireQueryMethod extends QueryMethod {
@SuppressWarnings("all")
protected static final String[] EMPTY_STRING_ARRAY = new String[0];
private final Method method;
private final GemfirePersistentEntity<?> entity;
private final Method method;
/**
* Creates a new {@link GemfireQueryMethod} from the given {@link Method} and {@link RepositoryMetadata}.
*
* @param method must not be {@literal null}.
* @param metadata must not be {@literal null}.
* @param factory must not be {@literal null}.
* @param context must not be {@literal null}.
* @param mappingContext must not be {@literal null}.
*/
public GemfireQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> context) {
MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> mappingContext) {
super(method, metadata, factory);
Assert.notNull(context);
Assert.notNull(mappingContext, "MappingContext must not be null");
assertNonPagingQueryMethod(method);
this.method = method;
this.entity = context.getPersistentEntity(getDomainClass());
this.entity = mappingContext.getPersistentEntity(getDomainClass()).orElseThrow(
() -> new IllegalArgumentException(String.format("Failed to resolve PersistentEntity for type [%s]",
getDomainClass())));
}
/**

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.repository.query;
import java.util.ArrayList;
@@ -29,11 +30,15 @@ import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* The QueryString class is a utility class for working with GemFire OQL query statement syntax.
* {@link QueryString} is a utility class used to construct GemFire OQL query statement syntax.
*
* @author Oliver Gierke
* @author David Turanski
* @author John Blum
* @see java.util.regex.Pattern
* @see org.springframework.data.domain.Sort
* @see org.springframework.data.gemfire.repository.query.support.OqlKeyword
* @see org.apache.geode.cache.Region
*/
public class QueryString {
@@ -117,8 +122,8 @@ public class QueryString {
*/
public QueryString bindIn(Collection<?> values) {
if (values != null) {
String valueString = StringUtils.collectionToDelimitedString(values, ", ", "'", "'");
return new QueryString(this.query.replaceFirst(IN_PATTERN, String.format("(%s)", valueString)));
return new QueryString(this.query.replaceFirst(IN_PATTERN, String.format("(%s)",
StringUtils.collectionToDelimitedString(values, ", ", "'", "'"))));
}
return this;
@@ -147,7 +152,7 @@ public class QueryString {
public Iterable<Integer> getInParameterIndexes() {
Pattern pattern = Pattern.compile(IN_PARAMETER_PATTERN);
Matcher matcher = pattern.matcher(query);
List<Integer> result = new ArrayList<Integer>();
List<Integer> result = new ArrayList<>();
while (matcher.find()) {
result.add(Integer.parseInt(matcher.group()));
@@ -166,7 +171,7 @@ public class QueryString {
* @see org.springframework.data.gemfire.repository.query.QueryString
*/
public QueryString orderBy(Sort sort) {
if (sort != null) {
if (hasSort(sort)) {
StringBuilder orderClause = new StringBuilder("ORDER BY ");
int count = 0;
@@ -181,6 +186,11 @@ public class QueryString {
return this;
}
/* (non-Javadoc) */
private boolean hasSort(Sort sort) {
return (sort != null && sort.iterator().hasNext());
}
/**
* Replaces the SELECT query with a SELECT DISTINCT query if the query does not contain the DISTINCT OQL keyword.
*

View File

@@ -36,11 +36,12 @@ import org.springframework.util.StringUtils;
*/
public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
private static final String INVALID_QUERY = "Paging and modifying queries are not supported!";
private static final String INVALID_QUERY = "Paging and modifying queries are not supported";
private boolean userDefinedQuery = false;
private final GemfireTemplate template;
private final QueryString query;
/*
@@ -74,7 +75,7 @@ public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
public StringBasedGemfireRepositoryQuery(String query, GemfireQueryMethod queryMethod, GemfireTemplate template) {
super(queryMethod);
Assert.notNull(template);
Assert.notNull(template, "GemfireTemplate must not be null");
this.userDefinedQuery |= !StringUtils.hasText(query);
this.query = new QueryString(StringUtils.hasText(query) ? query : queryMethod.getAnnotatedQuery());
@@ -108,11 +109,11 @@ public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
public Object execute(Object[] parameters) {
QueryMethod localQueryMethod = getQueryMethod();
QueryString query = (isUserDefinedQuery() ? this.query : this.query.forRegion(
localQueryMethod.getEntityInformation().getJavaType(), template.getRegion()));
QueryString query = (isUserDefinedQuery() ? this.query
: this.query.forRegion(localQueryMethod.getEntityInformation().getJavaType(), template.getRegion()));
ParametersParameterAccessor parameterAccessor = new ParametersParameterAccessor(
localQueryMethod.getParameters(), parameters);
ParametersParameterAccessor parameterAccessor =
new ParametersParameterAccessor(localQueryMethod.getParameters(), parameters);
for (Integer index : query.getInParameterIndexes()) {
query = query.bindIn(toCollection(parameterAccessor.getBindableValue(index - 1)));
@@ -144,7 +145,7 @@ public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
}
}
QueryString applyQueryAnnotationExtensions(final QueryMethod queryMethod, final QueryString queryString) {
QueryString applyQueryAnnotationExtensions(QueryMethod queryMethod, QueryString queryString) {
QueryString resolvedQueryString = queryString;
if (queryMethod instanceof GemfireQueryMethod) {
@@ -199,5 +200,4 @@ public class StringBasedGemfireRepositoryQuery extends GemfireRepositoryQuery {
return (source.getClass().isArray() ? CollectionUtils.arrayToList(source) : Collections.singletonList(source));
}
}

View File

@@ -16,8 +16,11 @@
package org.springframework.data.gemfire.repository.support;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Optional;
import org.apache.geode.cache.Region;
import org.springframework.data.gemfire.GemfireTemplate;
@@ -38,7 +41,6 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -80,8 +82,10 @@ public class GemfireRepositoryFactory extends RepositoryFactorySupport {
@Override
@SuppressWarnings("unchecked")
public <T, ID extends Serializable> GemfireEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
GemfirePersistentEntity<T> entity = (GemfirePersistentEntity<T>) mappingContext.getPersistentEntity(domainClass);
return new DefaultGemfireEntityInformation<T, ID>(entity);
GemfirePersistentEntity<T> entity = (GemfirePersistentEntity<T>) mappingContext.getPersistentEntity(domainClass)
.orElseThrow(() -> newIllegalArgumentException("Unable to resolve PersistentEntity for type [%s]", domainClass));
return new DefaultGemfireEntityInformation<>(entity);
}
/*
@@ -99,7 +103,9 @@ public class GemfireRepositoryFactory extends RepositoryFactorySupport {
}
GemfireTemplate getTemplate(RepositoryMetadata metadata) {
GemfirePersistentEntity<?> entity = mappingContext.getPersistentEntity(metadata.getDomainType());
GemfirePersistentEntity<?> entity = mappingContext.getPersistentEntity(metadata.getDomainType())
.orElseThrow(() -> newIllegalArgumentException("Unable to resolve PersistentEntity for type [%s]",
metadata.getDomainType()));
String entityRegionName = entity.getRegionName();
String repositoryRegionName = getRepositoryRegionName(metadata.getRepositoryInterface());
@@ -148,13 +154,11 @@ public class GemfireRepositoryFactory extends RepositoryFactorySupport {
* #getQueryLookupStrategy(Key, EvaluationContextProvider)
*/
@Override
protected QueryLookupStrategy getQueryLookupStrategy(Key key, EvaluationContextProvider evaluationContextProvider) {
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(Key key,
EvaluationContextProvider evaluationContextProvider) {
return new QueryLookupStrategy() {
@Override
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
NamedQueries namedQueries) {
return Optional.of(
(Method method, RepositoryMetadata metadata, ProjectionFactory factory, NamedQueries namedQueries) -> {
GemfireQueryMethod queryMethod = new GemfireQueryMethod(method, metadata, factory, mappingContext);
GemfireTemplate template = getTemplate(metadata);
@@ -169,7 +173,6 @@ public class GemfireRepositoryFactory extends RepositoryFactorySupport {
}
return new PartTreeGemfireRepositoryQuery(queryMethod, template);
}
};
});
}
}

View File

@@ -16,6 +16,8 @@
package org.springframework.data.gemfire.repository.support;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
@@ -23,6 +25,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.geode.cache.Cache;
@@ -78,7 +81,11 @@ public class SimpleGemfireRepository<T, ID extends Serializable> implements Gemf
*/
@Override
public <U extends T> U save(U entity) {
template.put(entityInformation.getId(entity), entity);
ID id = entityInformation.getId(entity).orElseThrow(
() -> newIllegalArgumentException("ID for entity [%s] is required", entity));
template.put(id, entity);
return entity;
}
@@ -88,15 +95,18 @@ public class SimpleGemfireRepository<T, ID extends Serializable> implements Gemf
*/
@Override
public <U extends T> Iterable<U> save(Iterable<U> entities) {
Map<ID, U> result = new HashMap<>();
Map<ID, U> entitiesToSave = new HashMap<>();
for (U entity : entities) {
result.put(entityInformation.getId(entity), entity);
ID id = entityInformation.getId(entity).orElseThrow(
() -> newIllegalArgumentException("ID for entity [%s] is required", entity));
entitiesToSave.put(id, entity);
}
template.putAll(result);
template.putAll(entitiesToSave);
return result.values();
return entitiesToSave.values();
}
/*
@@ -116,8 +126,10 @@ public class SimpleGemfireRepository<T, ID extends Serializable> implements Gemf
*/
@Override
public long count() {
SelectResults<Integer> results = template.find("SELECT count(*) FROM " + template.getRegion().getFullPath());
return (long) results.iterator().next();
SelectResults<Integer> results =
template.find(String.format("SELECT count(*) FROM %s", template.getRegion().getFullPath()));
return Long.valueOf(results.iterator().next());
}
/*
@@ -126,7 +138,7 @@ public class SimpleGemfireRepository<T, ID extends Serializable> implements Gemf
*/
@Override
public boolean exists(ID id) {
return (findOne(id) != null);
return findOne(id).isPresent();
}
/*
@@ -135,8 +147,8 @@ public class SimpleGemfireRepository<T, ID extends Serializable> implements Gemf
*/
@Override
@SuppressWarnings("unchecked")
public T findOne(ID id) {
return (T) template.get(id);
public Optional<T> findOne(ID id) {
return Optional.ofNullable(template.get(id));
}
/*
@@ -145,7 +157,9 @@ public class SimpleGemfireRepository<T, ID extends Serializable> implements Gemf
*/
@Override
public Collection<T> findAll() {
SelectResults<T> results = template.find("SELECT * FROM " + template.getRegion().getFullPath());
SelectResults<T> results =
template.find(String.format("SELECT * FROM %s", template.getRegion().getFullPath()));
return results.asList();
}
@@ -196,7 +210,7 @@ public class SimpleGemfireRepository<T, ID extends Serializable> implements Gemf
*/
@Override
public void delete(T entity) {
delete(entityInformation.getId(entity));
delete(entityInformation.getId(entity).orElseThrow(() -> new IllegalArgumentException("ID is required")));
}
/*

View File

@@ -0,0 +1,130 @@
/*
* Copyright 2016 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.gemfire.util;
import java.text.MessageFormat;
/**
* The {@link RuntimeExceptionFactory} class is a factory for creating common {@link RuntimeException RuntimeExceptions}
* with the added convenience of message formatting and optional {@link Throwable causes}.
*
* @author John Blum
* @since 1.0.0
*/
@SuppressWarnings("unused")
public abstract class RuntimeExceptionFactory {
/**
* Constructs and initializes an {@link IllegalArgumentException} with the given {@link String message}
* and {@link Object[] arguments} used to format the message.
*
* @param message {@link String} describing the exception.
* @param args {@link Object[] arguments} used in the message to replace format placeholders.
* @return a new {@link IllegalArgumentException} with the given {@link String message}.
* @see #newIllegalArgumentException(Throwable, String, Object...)
* @see java.lang.IllegalArgumentException
*/
public static IllegalArgumentException newIllegalArgumentException(String message, Object... args) {
return newIllegalArgumentException(null, message, args);
}
/**
* Constructs and initializes an {@link IllegalArgumentException} with the given {@link Throwable cause},
* {@link String message} and {@link Object[] arguments} used to format the message.
*
* @param cause {@link Throwable} identifying the reason the {@link IllegalArgumentException} was thrown.
* @param message {@link String} describing the exception.
* @param args {@link Object[] arguments} used in the message to replace format placeholders.
* @return a new {@link IllegalArgumentException} with the given {@link String message}.
* @see java.lang.IllegalArgumentException
*/
public static IllegalArgumentException newIllegalArgumentException(Throwable cause,
String message, Object... args) {
return new IllegalArgumentException(format(message, args), cause);
}
/**
* Constructs and initializes an {@link IllegalStateException} with the given {@link String message}
* and {@link Object[] arguments} used to format the message.
*
* @param message {@link String} describing the exception.
* @param args {@link Object[] arguments} used in the message to replace format placeholders.
* @return a new {@link IllegalStateException} with the given {@link String message}.
* @see #newIllegalStateException(Throwable, String, Object...)
* @see java.lang.IllegalStateException
*/
public static IllegalStateException newIllegalStateException(String message, Object... args) {
return newIllegalStateException(null, message, args);
}
/**
* Constructs and initializes an {@link IllegalStateException} with the given {@link Throwable cause},
* {@link String message} and {@link Object[] arguments} used to format the message.
*
* @param cause {@link Throwable} identifying the reason the {@link IllegalStateException} was thrown.
* @param message {@link String} describing the exception.
* @param args {@link Object[] arguments} used in the message to replace format placeholders.
* @return a new {@link IllegalStateException} with the given {@link String message}.
* @see java.lang.IllegalStateException
*/
public static IllegalStateException newIllegalStateException(Throwable cause, String message, Object... args) {
return new IllegalStateException(format(message, args), cause);
}
/**
* Constructs and initializes an {@link RuntimeException} with the given {@link String message}
* and {@link Object[] arguments} used to format the message.
*
* @param message {@link String} describing the exception.
* @param args {@link Object[] arguments} used in the message to replace format placeholders.
* @return a new {@link RuntimeException} with the given {@link String message}.
* @see #newRuntimeException(Throwable, String, Object...)
* @see java.lang.RuntimeException
*/
public static RuntimeException newRuntimeException(String message, Object... args) {
return newRuntimeException(null, message, args);
}
/**
* Constructs and initializes an {@link RuntimeException} with the given {@link Throwable cause},
* {@link String message} and {@link Object[] arguments} used to format the message.
*
* @param cause {@link Throwable} identifying the reason the {@link RuntimeException} was thrown.
* @param message {@link String} describing the exception.
* @param args {@link Object[] arguments} used in the message to replace format placeholders.
* @return a new {@link RuntimeException} with the given {@link String message}.
* @see java.lang.RuntimeException
*/
public static RuntimeException newRuntimeException(Throwable cause, String message, Object... args) {
return new RuntimeException(format(message, args), cause);
}
/**
* Formats the given {@link String message} using the given {@link Object[] arguments}.
*
* @param message {@link String} containing the message pattern to format.
* @param args {@link Object[] arguments} used in the message to replace format placeholders.
* @return the formatted {@link String message}.
* @see java.lang.String#format(String, Object...)
* @see java.text.MessageFormat#format(String, Object...)
*/
protected static String format(String message, Object... args) {
return MessageFormat.format(String.format(message, args), args);
}
}