org.sql2o.DefaultResultSetHandlerFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of anima Show documentation
Show all versions of anima Show documentation
Operate the database like a stream
package org.sql2o;
import org.sql2o.converters.Converter;
import org.sql2o.converters.ConverterException;
import org.sql2o.quirks.Quirks;
import org.sql2o.reflection.Getter;
import org.sql2o.reflection.Pojo;
import org.sql2o.reflection.PojoMetadata;
import org.sql2o.reflection.Setter;
import org.sql2o.tools.AbstractCache;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
public class DefaultResultSetHandlerFactory implements ResultSetHandlerFactory {
private final PojoMetadata metadata;
private final Quirks quirks;
public DefaultResultSetHandlerFactory(PojoMetadata pojoMetadata, Quirks quirks) {
this.metadata = pojoMetadata;
this.quirks = quirks;
}
@SuppressWarnings("unchecked")
private static Getter getGetter(final Quirks quirks, final String propertyPath, final PojoMetadata metadata) {
int index = propertyPath.indexOf('.');
if (index <= 0) {
// Simple path - fast way
final Getter getter = metadata.getPropertyGetterIfExists(propertyPath);
// behavior change: do not throw if POJO contains less properties
if (getter == null) return null;
final Converter> converter = quirks.converterOf(getter.getType());
// getter without converter
if (converter == null) return getter;
return new Getter() {
public Object getProperty(Object obj) {
try {
return converter.convert(getter.getProperty(obj));
} catch (ConverterException e) {
throw new Sql2oException("Error trying to convert column " + propertyPath + " to type " + getter.getType(), e);
}
}
public Class> getType() {
return getter.getType();
}
};
}
// dot path - long way
// i'm too lazy now to rewrite this case so I just call old unoptimized code...
// TODO: rewrite, get rid of POJO class
return new Getter() {
public Object getProperty(Object obj) {
Pojo pojo = new Pojo(metadata, metadata.isCaseSensitive(), obj);
return pojo.getProperty(propertyPath, quirks);
}
public Class> getType() {
// doesn't used anyway
return Object.class;
}
};
}
@SuppressWarnings("unchecked")
private static Setter getSetter(
final Quirks quirks,
final String propertyPath,
final PojoMetadata metadata) {
int index = propertyPath.indexOf('.');
if (index <= 0) {
// Simple path - fast way
final Setter setter = metadata.getPropertySetterIfExists(propertyPath);
// behavior change: do not throw if POJO contains less properties
if (setter == null) return null;
final Converter> converter = quirks.converterOf(setter.getType());
// setter without converter
if (converter == null) return setter;
return new Setter() {
public void setProperty(Object obj, Object value) {
try {
setter.setProperty(obj, converter.convert(value));
} catch (ConverterException e) {
throw new Sql2oException("Error trying to convert column " + propertyPath + " to type " + setter.getType(), e);
}
}
public Class> getType() {
return setter.getType();
}
};
}
// dot path - long way
// i'm too lazy now to rewrite this case so I just call old unoptimized code...
// TODO: rewrite, get rid of POJO class
return new Setter() {
public void setProperty(Object obj, Object value) {
Pojo pojo = new Pojo(metadata, metadata.isCaseSensitive(), obj);
pojo.setProperty(propertyPath, value, quirks);
}
public Class> getType() {
// doesn't used anyway
return Object.class;
}
};
}
private static class Key {
final String stringKey;
final DefaultResultSetHandlerFactory> f;
DefaultResultSetHandlerFactory> factory(){
return f;
}
private PojoMetadata getMetadata() {
return f.metadata;
}
private Quirks getQuirksMode() {
return f.quirks;
}
private Key(String stringKey, DefaultResultSetHandlerFactory> f) {
this.stringKey = stringKey;
this.f = f;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
return f.metadata.equals(key.getMetadata())
&& f.quirks == key.getQuirksMode()
&& stringKey.equals(key.stringKey);
}
@Override
public int hashCode() {
int result = f.metadata.hashCode();
result = 31 * result + f.quirks.hashCode();
result = 31 * result + stringKey.hashCode();
return result;
}
}
private static final AbstractCache,ResultSetMetaData>
c = new AbstractCache, ResultSetMetaData>() {
@Override
protected ResultSetHandler> evaluate(Key key, ResultSetMetaData param) {
try {
return key.factory().newResultSetHandler0(param);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
};
@SuppressWarnings("unchecked")
public ResultSetHandler newResultSetHandler(final ResultSetMetaData meta) throws SQLException {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 1; i <= meta.getColumnCount(); i++) {
stringBuilder.append(quirks.getColumnName(meta,i)).append("\n");
}
return (ResultSetHandler) c.get(new Key(stringBuilder.toString(), this),meta);
}
@SuppressWarnings("unchecked")
private ResultSetHandler newResultSetHandler0(final ResultSetMetaData meta) throws SQLException {
final Getter[] getters;
final Setter[] setters;
final Converter converter;
final boolean useExecuteScalar;
//TODO: it's possible to cache converter/setters/getters
// cache key is ResultSetMetadata + Bean type
converter = quirks.converterOf(metadata.getType());
final int columnCount = meta.getColumnCount();
getters = new Getter[columnCount + 1]; // getters[0] is always null
for (int i = 1; i <= columnCount; i++) {
String colName = quirks.getColumnName(meta, i);
// behavior change: do not throw if POJO contains less properties
getters[i] = getGetter(quirks, colName, metadata);
// If more than 1 column is fetched (we cannot fall back to executeScalar),
// and the getter doesn't exist, throw exception.
if (this.metadata.throwOnMappingFailure && getters[i] == null && columnCount > 1) {
throw new Sql2oException("Could not map " + colName + " to any property.");
}
}
setters = new Setter[columnCount + 1]; // setters[0] is always null
for (int i = 1; i <= columnCount; i++) {
String colName = quirks.getColumnName(meta, i);
setters[i] = getSetter(quirks, colName, metadata);
// If more than 1 column is fetched (we cannot fall back to executeScalar),
// and the setter doesn't exist, throw exception.
if (this.metadata.throwOnMappingFailure && setters[i] == null && columnCount > 1) {
throw new Sql2oException("Could not map " + colName + " to any property.");
}
}
/**
* Fallback to executeScalar if converter exists,
* we're selecting 1 column, and no property setter exists for the column.
*/
useExecuteScalar = converter != null && columnCount == 1 && setters[1] == null;
return new ResultSetHandler() {
@SuppressWarnings("unchecked")
public T handle(ResultSet resultSet) throws SQLException {
if (useExecuteScalar) {
try {
return (T) converter.convert(quirks.getRSVal(resultSet, 1));
} catch (ConverterException e) {
throw new Sql2oException("Error occurred while converting value from database to type " + metadata.getType(), e);
}
}
// otherwise we want executeAndFetch with object mapping
Object pojo = metadata.getObjectConstructor().newInstance();
for (int colIdx = 1; colIdx <= columnCount; colIdx++) {
Setter setter = setters[colIdx];
if (setter == null) continue;
setter.setProperty(pojo, quirks.getRSVal(resultSet, colIdx));
}
return (T) pojo;
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy