All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.helidon.common.mapper.MapperManager Maven / Gradle / Ivy

There is a newer version: 4.1.6
Show newest version
/*
 * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
 *
 * 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.common.mapper;

import java.util.List;
import java.util.Optional;
import java.util.ServiceLoader;

import io.helidon.common.GenericType;
import io.helidon.common.Prioritized;
import io.helidon.common.mapper.spi.MapperProvider;
import io.helidon.common.serviceloader.HelidonServiceLoader;

/**
 * Mapper manager of all configured mappers.
 * 

* To map a source to target, you can use either of the {@code map} methods defined in this interface, * as they make sure that the mapping exists in either space. *

    *
  • If you call {@link #map(Object, Class, Class)} and no mapper is found for the class pair, * the implementation calls the {@link #map(Object, io.helidon.common.GenericType, io.helidon.common.GenericType)} with * {@link io.helidon.common.GenericType}s created for each parameters
  • *
  • If you call {@link #map(Object, io.helidon.common.GenericType, io.helidon.common.GenericType)} and no mapper is * found for the {@link io.helidon.common.GenericType} pair, an attempt is to locate a mapper for * the underlying class *IF* the generic type represents a simple class (e.g. not a generic type declaration)
  • *
*/ public interface MapperManager { /** * Create a fluent API builder to create a customized mapper manager. * * @return a new builder */ static Builder builder() { return new Builder(); } /** * Create a mapper manager using only Java Service loader * loaded {@link io.helidon.common.mapper.spi.MapperProvider MapperProviders}. * * @return create a new mapper manager from service loader */ static MapperManager create() { return MapperManager.builder().build(); } /** * Create a fluent API builder to create a customized mapper manager based on the provided Helidon Service loader. * * @param serviceLoader fully configured service loader * @return a new builder */ static Builder builder(HelidonServiceLoader serviceLoader) { return MapperManager.builder() .mapperProviders(serviceLoader); } /** * Create a mapper manager using only the provided Helidon Service loader. * loaded {@link io.helidon.common.mapper.spi.MapperProvider MapperProviders}. * * @param serviceLoader fully configured service loader * @return create a new mapper manager from service loader */ static MapperManager create(HelidonServiceLoader serviceLoader) { return MapperManager.builder() .mapperProviders(serviceLoader) .build(); } /** * Map from source to target. * * @param source object to map * @param sourceType type of the source object (to locate the mapper) * @param targetType type of the target object (to locate the mapper) * @param type of the source * @param type of the target * @return result of the mapping * @throws MapperException in case the mapper was not found or failed */ TARGET map(SOURCE source, GenericType sourceType, GenericType targetType) throws MapperException; /** * Map from source to target. * * @param source object to map * @param sourceType class of the source object (to locate the mapper) * @param targetType class of the target object (to locate the mapper) * @param type of the source * @param type of the target * @return result of the mapping * @throws MapperException in case the mapper was not found or failed */ TARGET map(SOURCE source, Class sourceType, Class targetType) throws MapperException; /** * Fluent API builder for {@link io.helidon.common.mapper.MapperManager}. */ final class Builder implements io.helidon.common.Builder { private HelidonServiceLoader.Builder providers = HelidonServiceLoader .builder(ServiceLoader.load(MapperProvider.class)); private Builder() { } @Override public MapperManager build() { return new MapperManagerImpl(this); } private Builder mapperProviders(HelidonServiceLoader serviceLoader) { providers = HelidonServiceLoader.builder(ServiceLoader.load(MapperProvider.class)) .useSystemServiceLoader(false); serviceLoader.forEach(providers::addService); return this; } /** * Add a new {@link io.helidon.common.mapper.spi.MapperProvider} to the list of providers loaded from * system service loader. *

* You may add multiple instances of the same implementation class. *

* If the same provider implementation would be loaded by Java Service loader, the service loader instance is ignored. * If you need to add a new implementation of the same type, please use the full features * of the {@link io.helidon.common.serviceloader.HelidonServiceLoader} and invoke * {@link MapperManager#create(io.helidon.common.serviceloader.HelidonServiceLoader)}. * * @param provider prioritized mapper provider to use * @return updated builder instance */ public Builder addMapperProvider(MapperProvider provider) { this.providers.addService(provider); return this; } /** * Add a new {@link io.helidon.common.mapper.spi.MapperProvider} to the list of providers loaded * from system service loader with a custom priority. * * @param provider a mapper provider instance * @param priority priority of the provider (see {@link io.helidon.common.serviceloader.HelidonServiceLoader} * documentation for details about priority handling) * @return updated builder instance * @see #addMapperProvider(io.helidon.common.mapper.spi.MapperProvider) */ public Builder addMapperProvider(MapperProvider provider, int priority) { this.providers.addService(provider, priority); return this; } /** * Add a mapper to the list of mapper. * * @param mapper the mapper to map source instances to target instances * @param sourceType class of the source instance * @param targetType class of the target instance * @param type of source * @param type of target * @return updated builder instance */ public Builder addMapper(Mapper mapper, Class sourceType, Class targetType) { return addMapper(mapper, sourceType, targetType, Prioritized.DEFAULT_PRIORITY); } /** * Add a mapper to the list of mapper with a custom priority. * * @param mapper the mapper to map source instances to target instances * @param sourceType class of the source instance * @param targetType class of the target instance * @param type of source * @param type of target * @return updated builder instance */ public Builder addMapper(Mapper mapper, Class sourceType, Class targetType, int priority) { this.providers.addService(new MapperProvider() { @SuppressWarnings({"unchecked", "ObjectEquality"}) @Override public Optional> mapper(Class sourceClass, Class targetClass) { if ((sourceType == sourceClass) && (targetType == targetClass)) { return Optional.of((Mapper) mapper); } return Optional.empty(); } }, priority); return this; } /** * Add a mapper to the list of mapper. * * @param mapper the mapper to map source instances to target instances * @param sourceType generic type of the source instance * @param targetType generic type of the target instance * @param type of source * @param type of target * @return updated builder instance */ public Builder addMapper(Mapper mapper, GenericType sourceType, GenericType targetType) { return addMapper(mapper, sourceType, targetType, Prioritized.DEFAULT_PRIORITY); } /** * Add a mapper to the list of mapper with custom priority. * * @param mapper the mapper to map source instances to target instances * @param sourceType generic type of the source instance * @param targetType generic type of the target instance * @param type of source * @param type of target * @return updated builder instance */ public Builder addMapper(Mapper mapper, GenericType sourceType, GenericType targetType, int priority) { this.providers.addService(new MapperProvider() { @Override public Optional> mapper(Class sourceClass, Class targetClass) { return Optional.empty(); } @SuppressWarnings({"unchecked"}) @Override public Optional> mapper(GenericType sourceClass, GenericType targetClass) { if ((sourceType.equals(sourceClass)) && (targetType.equals(targetClass))) { return Optional.of((Mapper) mapper); } return Optional.empty(); } }, priority); return this; } // used by the implementation List mapperProviders() { return providers.build().asList(); } } }