io.helidon.dbclient.DbMapperManagerImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of helidon-dbclient Show documentation
Show all versions of helidon-dbclient Show documentation
Helidon Database Client API
/*
* Copyright (c) 2019, 2021 Oracle and/or its affiliates.
*
* 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 io.helidon.dbclient;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import io.helidon.common.GenericType;
import io.helidon.common.mapper.MapperException;
import io.helidon.dbclient.spi.DbMapperProvider;
/**
* Default implementation of the DbMapperManager.
*/
class DbMapperManagerImpl implements DbMapperManager {
public static final String ERROR_NO_MAPPER_FOUND = "Failed to find DB mapper.";
private final List providers;
private final Map, DbMapper>> byClass = new ConcurrentHashMap<>();
private final Map, DbMapper>> byType = new ConcurrentHashMap<>();
DbMapperManagerImpl(Builder builder) {
this.providers = builder.mapperProviders();
}
@Override
public T read(DbRow row, Class expectedType) {
return executeMapping(() -> findMapper(expectedType, false)
.read(row),
row,
TYPE_DB_ROW,
GenericType.create(expectedType));
}
@Override
public T read(DbRow row, GenericType expectedType) {
return executeMapping(() -> findMapper(expectedType, false)
.read(row),
row,
TYPE_DB_ROW,
expectedType);
}
@Override
public Map toNamedParameters(T value, Class valueClass) {
return executeMapping(() -> findMapper(valueClass, false)
.toNamedParameters(value),
value,
GenericType.create(valueClass),
TYPE_NAMED_PARAMS);
}
@Override
public List> toIndexedParameters(T value, Class valueClass) {
return executeMapping(() -> findMapper(valueClass, false)
.toIndexedParameters(value),
value,
GenericType.create(valueClass),
TYPE_INDEXED_PARAMS);
}
private T executeMapping(Supplier mapping, Object source, GenericType> sourceType, GenericType> targetType) {
try {
return mapping.get();
} catch (MapperException e) {
throw e;
} catch (Exception e) {
throw createMapperException(source, sourceType, targetType, e);
}
}
@SuppressWarnings("unchecked")
private DbMapper findMapper(Class type, boolean fromTypes) {
DbMapper> mapper = byClass.computeIfAbsent(type, aClass -> {
return fromProviders(type)
.orElseGet(() -> {
GenericType targetType = GenericType.create(type);
if (fromTypes) {
return notFoundMapper(targetType);
}
return findMapper(targetType, true);
});
});
return (DbMapper) mapper;
}
@SuppressWarnings("unchecked")
private DbMapper findMapper(GenericType type, boolean fromClasses) {
DbMapper> mapper = byType.computeIfAbsent(type, aType -> {
return fromProviders(type)
.orElseGet(() -> {
if (!fromClasses && type.isClass()) {
return findMapper((Class) type.rawType(), true);
}
return notFoundMapper(type);
});
});
return (DbMapper) mapper;
}
private Optional> fromProviders(Class type) {
return providers.stream()
.flatMap(provider -> provider.mapper(type).stream()).findFirst();
}
private Optional> fromProviders(GenericType type) {
return providers.stream()
.flatMap(provider -> provider.mapper(type).stream()).findFirst();
}
private RuntimeException createMapperException(Object source,
GenericType> sourceType,
GenericType> targetType,
Throwable throwable) {
throw new MapperException(sourceType,
targetType,
"Failed to map source of class '" + source.getClass().getName() + "'",
throwable);
}
private static DbMapper notFoundMapper(GenericType type) {
return new DbMapper() {
@Override
public T read(DbRow row) {
throw new MapperException(TYPE_DB_ROW, type, ERROR_NO_MAPPER_FOUND);
}
@Override
public Map toNamedParameters(T value) {
throw new MapperException(type, TYPE_NAMED_PARAMS, ERROR_NO_MAPPER_FOUND);
}
@Override
public List> toIndexedParameters(T value) {
throw new MapperException(type, TYPE_INDEXED_PARAMS, ERROR_NO_MAPPER_FOUND);
}
};
}
}