Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2017-2018 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
*
* https://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.cloud.gcp.data.datastore.core.convert;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.cloud.datastore.BaseEntity;
import com.google.cloud.datastore.EntityValue;
import com.google.cloud.datastore.FullEntity;
import com.google.cloud.datastore.IncompleteKey;
import com.google.cloud.datastore.ListValue;
import com.google.cloud.datastore.StringValue;
import com.google.cloud.datastore.Value;
import org.springframework.cloud.gcp.data.datastore.core.mapping.DatastoreDataException;
import org.springframework.cloud.gcp.data.datastore.core.mapping.DatastoreMappingContext;
import org.springframework.cloud.gcp.data.datastore.core.mapping.DatastorePersistentEntity;
import org.springframework.cloud.gcp.data.datastore.core.mapping.DatastorePersistentProperty;
import org.springframework.cloud.gcp.data.datastore.core.mapping.EmbeddedType;
import org.springframework.data.convert.EntityInstantiator;
import org.springframework.data.convert.EntityInstantiators;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
import static org.springframework.cloud.gcp.data.datastore.core.mapping.EmbeddedType.NOT_EMBEDDED;
/**
* A class for object to entity and entity to object conversions.
*
* @author Dmitry Solomakha
* @author Chengyuan Zhao
*
* @since 1.1
*/
public class DefaultDatastoreEntityConverter implements DatastoreEntityConverter {
private DatastoreMappingContext mappingContext;
private final EntityInstantiators instantiators = new EntityInstantiators();
private final ReadWriteConversions conversions;
public DefaultDatastoreEntityConverter(DatastoreMappingContext mappingContext,
ObjectToKeyFactory objectToKeyFactory) {
this(mappingContext,
new TwoStepsConversions(new DatastoreCustomConversions(), objectToKeyFactory, mappingContext));
}
public DefaultDatastoreEntityConverter(DatastoreMappingContext mappingContext, ReadWriteConversions conversions) {
this.mappingContext = mappingContext;
this.conversions = conversions;
conversions.registerEntityConverter(this);
}
@Override
public ReadWriteConversions getConversions() {
return this.conversions;
}
@Override
public Map readAsMap(BaseEntity entity, TypeInformation mapTypeInformation) {
Assert.notNull(mapTypeInformation, "mapTypeInformation can't be null");
if (entity == null) {
return null;
}
Map result;
if (!mapTypeInformation.getType().isInterface()) {
try {
result = (Map) ((Constructor) mapTypeInformation.getType().getConstructor()).newInstance();
}
catch (Exception e) {
throw new DatastoreDataException("Unable to create an instance of a custom map type: "
+ mapTypeInformation.getType()
+ " (make sure the class is public and has a public no-args constructor)", e);
}
}
else {
result = new HashMap<>();
}
EntityPropertyValueProvider propertyValueProvider = new EntityPropertyValueProvider(
entity, this.conversions);
Set fieldNames = entity.getNames();
for (String field : fieldNames) {
result.put(this.conversions.convertOnRead(field, NOT_EMBEDDED, mapTypeInformation.getComponentType()),
propertyValueProvider.getPropertyValue(field,
EmbeddedType.of(mapTypeInformation.getMapValueType()),
mapTypeInformation.getMapValueType()));
}
return result;
}
@Override
public Map readAsMap(Class keyType, TypeInformation componentType,
BaseEntity entity) {
if (entity == null) {
return null;
}
Map result = new HashMap<>();
return readAsMap(entity, ClassTypeInformation.from(result.getClass()));
}
@Override
@SuppressWarnings("unchecked")
public R read(Class aClass, BaseEntity entity) {
if (entity == null) {
return null;
}
DatastorePersistentEntity ostensiblePersistentEntity = (DatastorePersistentEntity) this.mappingContext
.getPersistentEntity(aClass);
if (ostensiblePersistentEntity == null) {
throw new DatastoreDataException("Unable to convert Datastore Entity to " + aClass);
}
EntityPropertyValueProvider propertyValueProvider = new EntityPropertyValueProvider(entity, this.conversions);
DatastorePersistentEntity persistentEntity = getDiscriminationPersistentEntity(ostensiblePersistentEntity,
propertyValueProvider);
ParameterValueProvider parameterValueProvider =
new PersistentEntityParameterValueProvider<>(persistentEntity, propertyValueProvider, null);
EntityInstantiator instantiator = this.instantiators.getInstantiatorFor(persistentEntity);
Object instance;
try {
instance = instantiator.createInstance(persistentEntity, parameterValueProvider);
PersistentPropertyAccessor accessor = persistentEntity.getPropertyAccessor(instance);
persistentEntity.doWithColumnBackedProperties((datastorePersistentProperty) -> {
// if a property is a constructor argument, it was already computed on instantiation
if (!persistentEntity.isConstructorArgument(datastorePersistentProperty)) {
Object value = propertyValueProvider
.getPropertyValue(datastorePersistentProperty);
if (value != null) {
accessor.setProperty(datastorePersistentProperty, value);
}
}
});
}
catch (DatastoreDataException ex) {
throw new DatastoreDataException("Unable to read " + persistentEntity.getName() + " entity", ex);
}
return (R) instance;
}
private DatastorePersistentEntity getDiscriminationPersistentEntity(DatastorePersistentEntity ostensibleEntity,
EntityPropertyValueProvider propertyValueProvider) {
if (ostensibleEntity.getDiscriminationFieldName() == null) {
return ostensibleEntity;
}
Set members = DatastoreMappingContext.getDiscriminationFamily(ostensibleEntity.getType());
Optional persistentEntity = members == null ? Optional.empty()
: members.stream().map(x -> (DatastorePersistentEntity) this.mappingContext.getPersistentEntity(x))
.filter(x -> x != null && isDiscriminationFieldMatch(x, propertyValueProvider)).findFirst();
return persistentEntity.orElse(ostensibleEntity);
}
private boolean isDiscriminationFieldMatch(DatastorePersistentEntity entity,
EntityPropertyValueProvider propertyValueProvider) {
return ((String[]) propertyValueProvider.getPropertyValue(entity.getDiscriminationFieldName(),
NOT_EMBEDDED,
ClassTypeInformation.from(String[].class)))[0].equals(entity.getDiscriminatorValue());
}
@Override
@SuppressWarnings("unchecked")
public void write(Object source, BaseEntity.Builder sink) {
DatastorePersistentEntity persistentEntity = this.mappingContext.getPersistentEntity(source.getClass());
String discriminationFieldName = persistentEntity.getDiscriminationFieldName();
List discriminationValues = persistentEntity.getCompatibleDiscriminationValues();
if (!discriminationValues.isEmpty() || discriminationFieldName != null) {
sink.set(discriminationFieldName,
discriminationValues.stream().map(StringValue::of).collect(Collectors.toList()));
}
PersistentPropertyAccessor accessor = persistentEntity.getPropertyAccessor(source);
persistentEntity.doWithColumnBackedProperties(
(DatastorePersistentProperty persistentProperty) -> {
// Datastore doesn't store its Key as a regular field.
if (persistentProperty.isIdProperty()) {
return;
}
try {
Object val = accessor.getProperty(persistentProperty);
Value convertedVal = this.conversions.convertOnWrite(val, persistentProperty);
if (persistentProperty.isUnindexed()) {
convertedVal = setExcludeFromIndexes(convertedVal);
}
sink.set(persistentProperty.getFieldName(), convertedVal);
}
catch (DatastoreDataException ex) {
throw new DatastoreDataException(
"Unable to write "
+ persistentEntity.kindName() + "." + persistentProperty.getFieldName(),
ex);
}
});
}
private Value setExcludeFromIndexes(Value convertedVal) {
// ListValues must have its contents individually excluded instead.
// the entire list must NOT be excluded or there will be an exception.
// Same for maps and embedded entities which are stored as EntityValue.
if (convertedVal.getClass().equals(EntityValue.class)) {
FullEntity.Builder builder = FullEntity.newBuilder();
((EntityValue) convertedVal).get().getProperties()
.forEach((key, value) -> builder.set(key, setExcludeFromIndexes(value)));
return EntityValue.of(builder.build());
}
else if (convertedVal.getClass().equals(ListValue.class)) {
return ListValue.of((List) ((ListValue) convertedVal).get().stream()
.map(this::setExcludeFromIndexes).collect(Collectors.toList()));
}
else {
return convertedVal.toBuilder().setExcludeFromIndexes(true).build();
}
}
}