Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,18 @@
import org.springframework.core.convert.ConverterNotFoundException;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.CustomConversions;
import org.springframework.data.jdbc.core.convert.ResultSetWrapper.SpecialColumnValue;
import org.springframework.data.jdbc.core.mapping.AggregateReference;
import org.springframework.data.jdbc.support.JdbcUtil;
import org.springframework.data.mapping.MappingException;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.mapping.PreferredConstructor;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.relational.core.conversion.BasicRelationalConverter;
import org.springframework.data.relational.core.conversion.RelationalConverter;
import org.springframework.data.relational.core.mapping.Embedded;
import org.springframework.data.relational.core.mapping.Embedded.OnEmpty;
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
Expand All @@ -59,10 +59,10 @@
* @author Jens Schauder
* @author Christoph Strobl
* @author Myeonghyeon Lee
* @since 1.1
* @see MappingContext
* @see SimpleTypeHolder
* @see CustomConversions
* @since 1.1
*/
public class BasicJdbcConverter extends BasicRelationalConverter implements JdbcConverter {

Expand Down Expand Up @@ -146,7 +146,7 @@ private Class<?> getReferenceColumnType(RelationalPersistentProperty property) {
return getColumnType(referencedEntity.getRequiredIdProperty());
}

/*
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.convert.JdbcConverter#getSqlType(org.springframework.data.relational.core.mapping.RelationalPersistentProperty)
*/
Expand All @@ -155,7 +155,7 @@ public int getSqlType(RelationalPersistentProperty property) {
return JdbcUtil.sqlTypeFor(getColumnType(property));
}

/*
/*
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.convert.JdbcConverter#getColumnType(org.springframework.data.relational.core.mapping.RelationalPersistentProperty)
*/
Expand Down Expand Up @@ -199,8 +199,8 @@ private Class<?> doGetColumnType(RelationalPersistentProperty property) {
@Nullable
public Object readValue(@Nullable Object value, TypeInformation<?> type) {

if (null == value) {
return null;
if (value == null || value == SpecialColumnValue.NO_SUCH_COLUMN) {
return value;
}

if (getConversions().hasCustomReadTarget(value.getClass(), type.getType())) {
Expand Down Expand Up @@ -322,30 +322,34 @@ private JdbcValue tryToConvertToJdbcValue(@Nullable Object value) {

@SuppressWarnings("unchecked")
@Override
public <T> T mapRow(RelationalPersistentEntity<T> entity, ResultSet resultSet, Object key) {
public <T> T mapRow(RelationalPersistentEntity<T> entity, ResultSetWrapper resultSet, Object key) {
return new ReadingContext<T>(
new PersistentPropertyPathExtension(
getMappingContext(), entity),
resultSet, Identifier.empty(), key).mapRow();
}

@Override
public <T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key) {
public <T> T mapRow(PersistentPropertyPathExtension path, ResultSetWrapper resultSet, Identifier identifier,
Object key) {
return new ReadingContext<T>(path, resultSet, identifier, key).mapRow();
}

private class ReadingContext<T> {

private final RelationalPersistentEntity<T> entity;

private final ResultSet resultSet;
private final ResultSetWrapper resultSet;
private final PersistentPropertyPathExtension rootPath;
private final PersistentPropertyPathExtension path;
private final Identifier identifier;
private final Object key;

private final PropertyValueProvider<RelationalPersistentProperty> propertyValueProvider;
private final PropertyValueProvider<RelationalPersistentProperty> backReferencePropertyValueProvider;

@SuppressWarnings("unchecked")
private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSet resultSet, Identifier identifier,
private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSetWrapper resultSet, Identifier identifier,
Object key) {

RelationalPersistentEntity<T> entity = (RelationalPersistentEntity<T>) rootPath.getLeafEntity();
Expand All @@ -360,9 +364,12 @@ private ReadingContext(PersistentPropertyPathExtension rootPath, ResultSet resul
this.entity);
this.identifier = identifier;
this.key = key;
propertyValueProvider = new JdbcPropertyValueProvider(identifierProcessing, path, resultSet);
backReferencePropertyValueProvider = new JdbcBackReferencePropertyValueProvider(identifierProcessing, path,
resultSet);
}

private ReadingContext(RelationalPersistentEntity<T> entity, ResultSet resultSet,
private ReadingContext(RelationalPersistentEntity<T> entity, ResultSetWrapper resultSet,
PersistentPropertyPathExtension rootPath, PersistentPropertyPathExtension path, Identifier identifier,
Object key) {

Expand All @@ -372,6 +379,10 @@ private ReadingContext(RelationalPersistentEntity<T> entity, ResultSet resultSet
this.path = path;
this.identifier = identifier;
this.key = key;

propertyValueProvider = new JdbcPropertyValueProvider(identifierProcessing, path, resultSet);
backReferencePropertyValueProvider = new JdbcBackReferencePropertyValueProvider(identifierProcessing, path,
resultSet);
}

private <S> ReadingContext<S> extendBy(RelationalPersistentProperty property) {
Expand Down Expand Up @@ -401,7 +412,11 @@ private T populateProperties(T instance, @Nullable Object idValue) {
continue;
}

propertyAccessor.setProperty(property, readOrLoadProperty(idValue, property));
Object value = readOrLoadProperty(idValue, property);
if (value != SpecialColumnValue.NO_SUCH_COLUMN) {
propertyAccessor.setProperty(property, value);
}

}

return propertyAccessor.getBean();
Expand Down Expand Up @@ -448,12 +463,12 @@ private Iterable<Object> resolveRelation(@Nullable Object id, RelationalPersiste
private Object readFrom(RelationalPersistentProperty property) {

if (property.isEntity()) {
return readEntityFrom(property, path);
return readEntityFrom(property);
}

Object value = getObjectFromResultSet(
path.extendBy(property).getColumnAlias().getReference(identifierProcessing));
return readValue(value, property.getTypeInformation());
Object value = propertyValueProvider.getPropertyValue(property);
return value == SpecialColumnValue.NO_SUCH_COLUMN ? SpecialColumnValue.NO_SUCH_COLUMN
: readValue(value, property.getTypeInformation());
}

@Nullable
Expand All @@ -469,7 +484,7 @@ private Object readEmbeddedEntityFrom(@Nullable Object idValue, RelationalPersis
}

private boolean shouldCreateEmptyEmbeddedInstance(RelationalPersistentProperty property) {
return OnEmpty.USE_EMPTY.equals(property.findAnnotation(Embedded.class).onEmpty());
return property.shouldCreateEmptyEmbedded();
}

private boolean hasInstanceValues(@Nullable Object idValue) {
Expand All @@ -485,7 +500,8 @@ private boolean hasInstanceValues(@Nullable Object idValue) {
return true;
}

if (readOrLoadProperty(idValue, embeddedProperty) != null) {
Object value = readOrLoadProperty(idValue, embeddedProperty);
if (value != null && value != SpecialColumnValue.NO_SUCH_COLUMN) {
return true;
}
}
Expand All @@ -495,7 +511,7 @@ private boolean hasInstanceValues(@Nullable Object idValue) {

@Nullable
@SuppressWarnings("unchecked")
private Object readEntityFrom(RelationalPersistentProperty property, PersistentPropertyPathExtension path) {
private Object readEntityFrom(RelationalPersistentProperty property) {

ReadingContext<?> newContext = extendBy(property);
RelationalPersistentEntity<?> entity = getMappingContext().getRequiredPersistentEntity(property.getActualType());
Expand All @@ -506,8 +522,7 @@ private Object readEntityFrom(RelationalPersistentProperty property, PersistentP
if (idProperty != null) {
idValue = newContext.readFrom(idProperty);
} else {
idValue = newContext.getObjectFromResultSet(
path.extendBy(property).getReverseColumnNameAlias().getReference(identifierProcessing));
idValue = backReferencePropertyValueProvider.getPropertyValue(property);
}

if (idValue == null) {
Expand All @@ -517,16 +532,6 @@ private Object readEntityFrom(RelationalPersistentProperty property, PersistentP
return newContext.createInstanceInternal(idValue);
}

@Nullable
private Object getObjectFromResultSet(String backreferenceName) {

try {
return resultSet.getObject(backreferenceName);
} catch (SQLException o_O) {
throw new MappingException(String.format("Could not read value %s from result set!", backreferenceName), o_O);
}
}

private T createInstanceInternal(@Nullable Object idValue) {

T instance = createInstance(entity, parameter -> {
Expand All @@ -537,7 +542,16 @@ private T createInstanceInternal(@Nullable Object idValue) {

RelationalPersistentProperty property = entity.getRequiredPersistentProperty(parameterName);

return readOrLoadProperty(idValue, property);
Object value = readOrLoadProperty(idValue, property);

if (value == SpecialColumnValue.NO_SUCH_COLUMN) {

throw new MappingException(
String.format("Couldn't create instance of type %s with id. No column found for argument named '%s'.",
entity.getType(), parameterName));
}

return value;
});
return populateProperties(instance, idValue);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ public EntityRowMapper(RelationalPersistentEntity<T> entity, JdbcConverter conve
@Override
public T mapRow(ResultSet resultSet, int rowNumber) {

return path == null ? converter.mapRow(entity, resultSet, rowNumber)
: converter.mapRow(path, resultSet, identifier, rowNumber);
ResultSetWrapper wrappedResultSet = new ResultSetWrapper(resultSet);

return path == null //
? converter.mapRow(entity, wrappedResultSet, rowNumber) //
: converter.mapRow(path, wrappedResultSet, identifier, rowNumber);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2020 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.data.jdbc.core.convert;

import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.relational.core.sql.IdentifierProcessing;

/**
* {@link PropertyValueProvider} obtaining values from a {@link ResultSetWrapper}.
* For a given id property it provides the value in the resultset under which other entities refer back to it.
*
*
* @author Jens Schauder
* @since 2.0
*/
class JdbcBackReferencePropertyValueProvider implements PropertyValueProvider<RelationalPersistentProperty> {

private final IdentifierProcessing identifierProcessing;
private final PersistentPropertyPathExtension basePath;
private final ResultSetWrapper resultSet;


/**
* @param identifierProcessing used for converting the {@link org.springframework.data.relational.core.sql.SqlIdentifier} from a property to a column label
* @param basePath path from the aggregate root relative to which all properties get resolved.
* @param resultSet the {@link ResultSetWrapper} from which to obtain the actual values.
*/
JdbcBackReferencePropertyValueProvider(IdentifierProcessing identifierProcessing, PersistentPropertyPathExtension basePath, ResultSetWrapper resultSet) {

this.resultSet = resultSet;
this.basePath = basePath;
this.identifierProcessing = identifierProcessing;
}

@Override
public <T> T getPropertyValue(RelationalPersistentProperty property) {
return (T)resultSet.getObject(basePath.extendBy(property).getReverseColumnNameAlias().getReference(identifierProcessing));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public interface JdbcConverter extends RelationalConverter {
* @param <T>
* @return
*/
<T> T mapRow(RelationalPersistentEntity<T> entity, ResultSet resultSet, Object key);
<T> T mapRow(RelationalPersistentEntity<T> entity, ResultSetWrapper resultSet, Object key);

/**
* Read the current row from {@link ResultSet} to an {@link PersistentPropertyPathExtension#getActualType() entity}.
Expand All @@ -66,7 +66,7 @@ public interface JdbcConverter extends RelationalConverter {
* @param <T>
* @return
*/
<T> T mapRow(PersistentPropertyPathExtension path, ResultSet resultSet, Identifier identifier, Object key);
<T> T mapRow(PersistentPropertyPathExtension path, ResultSetWrapper resultSet, Identifier identifier, Object key);

/**
* The type to be used to store this property in the database. Multidimensional arrays are unwrapped to reflect a
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2020 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.data.jdbc.core.convert;

import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.relational.core.sql.IdentifierProcessing;

/**
* {@link PropertyValueProvider} obtaining values from a {@link ResultSetWrapper}.
*
* @author Jens Schauder
* @since 2.0
*/
class JdbcPropertyValueProvider implements PropertyValueProvider<RelationalPersistentProperty> {

private final IdentifierProcessing identifierProcessing;
private final PersistentPropertyPathExtension basePath;
private final ResultSetWrapper resultSet;

/**
* @param identifierProcessing used for converting the {@link org.springframework.data.relational.core.sql.SqlIdentifier} from a property to a column label
* @param basePath path from the aggregate root relative to which all properties get resolved.
* @param resultSet the {@link ResultSetWrapper} from which to obtain the actual values.
*/
JdbcPropertyValueProvider(IdentifierProcessing identifierProcessing, PersistentPropertyPathExtension basePath,
ResultSetWrapper resultSet) {

this.resultSet = resultSet;
this.basePath = basePath;
this.identifierProcessing = identifierProcessing;
}

@Override
public <T> T getPropertyValue(RelationalPersistentProperty property) {

String columnName = basePath.extendBy(property).getColumnAlias().getReference(identifierProcessing);
return (T) resultSet.getObject(columnName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
import java.util.Map;

import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
import org.springframework.data.relational.domain.Identifier;
import org.springframework.data.relational.core.sql.IdentifierProcessing;
import org.springframework.data.relational.core.sql.SqlIdentifier;
import org.springframework.data.relational.domain.Identifier;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.lang.NonNull;

Expand Down Expand Up @@ -54,6 +54,6 @@ public Map.Entry<Object, T> mapRow(ResultSet rs, int rowNum) throws SQLException
}

private T mapEntity(ResultSet resultSet, Object key) {
return converter.mapRow(path, resultSet, identifier, key);
return converter.mapRow(path, new ResultSetWrapper(resultSet), identifier, key);
}
}
Loading