Skip to content

Commit

Permalink
SQL serialization bug fixes for null and complex value types
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonDan committed Feb 15, 2020
1 parent 3f7f3fa commit d8c93b2
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ default VALUE fromPersistent(VALUE pSerialValue)
{
return pSerialValue;
}

@Override
default Class<VALUE> getSerialValueType()
{
return getDataType();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,9 @@ public interface ISerializableField<VALUE, SERIAL extends Serializable> extends
* @return the original field value
*/
VALUE fromPersistent(SERIAL pSerialValue);

/**
* The serial value's type.
*/
Class<SERIAL> getSerialValueType();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ default VALUE fromPersistent(String pSerialString)
{
return new Gson().fromJson(pSerialString, getDataType());
}

@Override
default Class<String> getSerialValueType()
{
return String.class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ public Long toPersistent(Instant pValue)
return pValue.toEpochMilli();
}

@Override
public Class<Long> getSerialValueType()
{
return Long.class;
}

@Override
public Instant fromPersistent(Long pSerialValue)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ public ENUM fromPersistent(String pSerialString)
}
}

@Override
public Class<String> getSerialValueType()
{
return String.class;
}

@Override
public ENUM copyValue(ENUM pEnum, ECopyMode pMode, CustomFieldCopy<?>... pCustomFieldCopies)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.sql.*;
import java.util.List;
import java.util.function.Supplier;
import java.util.logging.Logger;

/**
* Implementation of a statement executor based on a function that will be provided with a {@link PreparedStatement}.
Expand All @@ -17,6 +18,8 @@
*/
class StatementExecutor<RESULT> implements IStatementExecutor<RESULT>
{
private static final Logger LOGGER = Logger.getLogger(StatementExecutor.class.getName());

private final Supplier<Connection> connectionSupplier;
private final ThrowingFunction<PreparedStatement, RESULT, SQLException> executor;
private Connection connection;
Expand Down Expand Up @@ -47,7 +50,9 @@ public RESULT executeStatement(String pSQLStatement, List<ISerialValue> pArgs)
for (ISerialValue arg : pArgs)
arg.applyToStatement(statement, argIndex++);

return executor.apply(statement);
final RESULT result = executor.apply(statement);
LOGGER.info("SQL executed: " + pSQLStatement);
return result;
}
catch (SQLException pE)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ public <KEY, COLUMN extends IColumnIdentification<?>> Map<KEY, Object> toMap(COL
{
//noinspection unchecked
return Stream.of(pColumnsToInclude)
.collect(Collectors.toMap(pColumnMapper, pColumn -> get((IColumnIdentification) pColumn)));
//Allow null values
.collect(HashMap::new, (pMap, pColumn) -> pMap.put(pColumnMapper.apply(pColumn), get((IColumnIdentification) pColumn)), HashMap::putAll);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
public class DefaultValueSerializer implements IValueSerializer
{
private static final Map<Class, _SupportedSerialization<?, ?>> SUPPORTED_SERIALIZATIONS = new HashMap<>();
protected static final ISerialValue NULL_SERIAL_VALUE = new _NullSerialValue();

/*
* Adds all supported data types.
Expand Down Expand Up @@ -58,8 +59,7 @@ public <VALUE> ISerialValue toSerial(IColumnValueTuple<VALUE> pColumnValueTuple)
@Nullable
public <VALUE> VALUE fromSerial(IColumnIdentification<VALUE> pColumn, ResultSet pResultSet, int pIndex)
{
final _SupportedSerialization<VALUE, ?> serialization = _getSerializationForType(pColumn.getDataType());
return serialization.retrieveConvertedResult(pResultSet, pIndex);
return retrieveSerialValue(pColumn.getDataType(), pResultSet, pIndex);
}

/**
Expand All @@ -73,7 +73,7 @@ public <VALUE> VALUE fromSerial(IColumnIdentification<VALUE> pColumn, ResultSet
protected <VALUE, SERIAL extends Serializable> ISerialValue createSerialValue(Class<VALUE> pDataType, VALUE pDataValue)
{
if (pDataValue == null)
return null;
return NULL_SERIAL_VALUE;

final _SupportedSerialization<VALUE, SERIAL> serialization = _getSerializationForType(pDataType);

Expand All @@ -96,6 +96,21 @@ public void applyToStatement(PreparedStatement pStatement, int pIndex)
};
}

/**
* Retrieves a value from a {@link ResultSet} and converts it back to its original data value.
*
* @param pValueType the value type to retrieve
* @param pResultSet the SQL result set to retrieve the value from
* @param pIndex the index to retrieve the result from
* @return the original data value
*/
@Nullable
protected <VALUE> VALUE retrieveSerialValue(Class<VALUE> pValueType, ResultSet pResultSet, int pIndex)
{
final _SupportedSerialization<VALUE, ?> serialization = _getSerializationForType(pValueType);
return serialization.retrieveConvertedResult(pResultSet, pIndex);
}

/**
* Resolves a {@link _SupportedSerialization} for a specific data type.
* Throws a {@link OJDatabaseException} if the data type is not supported.
Expand Down Expand Up @@ -237,4 +252,23 @@ private interface _ResultRetriever<SERIAL>
*/
SERIAL retrieveResult(ResultSet pResultSet, int pIndex) throws SQLException;
}

/**
* Null serial value.
*/
private static class _NullSerialValue implements ISerialValue
{
@Override
public void applyToStatement(PreparedStatement pStatement, int pIndex)
{
try
{
pStatement.setObject(pIndex, null);
}
catch (SQLException pE)
{
throw new OJDatabaseException("Unable to apply parameter to statement!", pE);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ private <VALUE, SERIAL extends Serializable> ISerialValue _toSerialValue(FieldVa
final VALUE value = pTuple.getValue();

if (value == null)
return null;
return NULL_SERIAL_VALUE;

if (!(field instanceof ISerializableField))
throw new BeanSerializationException(_notSerializableMessage(field, true));
Expand All @@ -70,19 +70,21 @@ private <VALUE, SERIAL extends Serializable> ISerialValue _toSerialValue(FieldVa
* @param <VALUE> the data type of the bean field
* @return the converted data value
*/
@SuppressWarnings("unchecked")
private <VALUE, SERIAL extends Serializable> VALUE _fromPersistent(IColumnIdentification<?> pColumn, ResultSet pResultSet, int pIndex)
{
final SERIAL serialValue = (SERIAL) super.fromSerial(pColumn, pResultSet, pIndex);

if (!(pColumn instanceof IBeanFieldTupleBased))
return (VALUE) serialValue;
if (!(pColumn instanceof IBeanFieldBased))
//noinspection unchecked
return (VALUE) super.fromSerial(pColumn, pResultSet, pIndex);

final IField<VALUE> field = ((IBeanFieldTupleBased<VALUE>) pColumn).getFieldValueTuple().getField();
//noinspection unchecked
final IField<VALUE> field = ((IBeanFieldBased<VALUE>) pColumn).getBeanField();
if (!(field instanceof ISerializableField))
throw new BeanSerializationException(_notSerializableMessage(field, false));

return ((ISerializableField<VALUE, SERIAL>) field).fromPersistent(serialValue);
final ISerializableField<VALUE, SERIAL> serializableField = (ISerializableField<VALUE, SERIAL>) field;
final SERIAL serialValue = retrieveSerialValue(serializableField.getSerialValueType(), pResultSet, pIndex);

return serializableField.fromPersistent(serialValue);
}

/**
Expand Down

0 comments on commit d8c93b2

Please sign in to comment.