/*
* 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.jdbi.v3.core.mapper;
import java.lang.reflect.Type;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.jdbi.v3.core.statement.StatementContext;
/**
* A {@link RowMapper} implementation to easily compose existing
* RowMappers. As the name implies, it is most commonly used
* for retrieving multiple tables' Java representations from a
* joined row.
*/
public class JoinRowMapper implements RowMapper<JoinRowMapper.JoinRow>
{
/**
* Holder for a single joined row.
*/
public static class JoinRow
{
private final Map<Type, Object> entries;
private JoinRow(Map<Type, Object> entries) {
this.entries = entries;
}
/**
* Return the value mapped for a given class.
* @param klass the type that was mapped
* @return the value for that type
*/
public <T> T get(Class<T> klass) {
return klass.cast(get((Type)klass));
}
/**
* Return the value mapped for a given type.
* @param type the type that was mapped
* @return the value for that type
*/
public Object get(Type type) {
Object result = entries.get(type);
if (result == null && !entries.containsKey(type)) {
throw new IllegalArgumentException("no result stored for " + type);
}
return result;
}
}
private final Type[] types;
private JoinRowMapper(Type[] types)
{
this.types = types;
}
@Override
public JoinRow map(ResultSet r, StatementContext ctx)
throws SQLException
{
final Map<Type, Object> entries = new HashMap<>(types.length);
for (Type type : types) {
entries.put(type, ctx.findRowMapperFor(type)
.orElseThrow(() -> new IllegalArgumentException(
"No row mapper registered for " + type))
.map(r, ctx));
}
return new JoinRow(entries);
}
@Override
public RowMapper<JoinRow> specialize(ResultSet r, StatementContext ctx) throws SQLException {
RowMapper<?>[] mappers = new RowMapper[types.length];
for (int i = 0; i < types.length; i++) {
Type type = types[i];
mappers[i] = ctx.findRowMapperFor(type)
.orElseThrow(() -> new IllegalArgumentException("No row mapper registered for " + type))
.specialize(r, ctx);
}
return (rs, context) -> {
final Map<Type, Object> entries = new HashMap<>(types.length);
for (int i = 0; i < types.length; i++) {
Type type = types[i];
RowMapper<?> mapper = mappers[i];
entries.put(type, mapper.map(r, ctx));
}
return new JoinRow(entries);
};
}
/**
* Create a JoinRowMapper that maps each of the given types and returns a
* {@link JoinRowMapper.JoinRow} with the resulting values.
* @param classes the types to extract
* @return a JoinRowMapper that extracts the given types
*/
public static JoinRowMapper forTypes(Type... classes)
{
return new JoinRowMapper(classes);
}
}