org.mapstruct.factory.Mappers Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapstruct Show documentation
Show all versions of mapstruct Show documentation
An annotation processor for generating type-safe bean mappers
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.factory;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import org.mapstruct.Mapper;
/**
* Factory for obtaining mapper instances if no explicit component model such as CDI is configured via
* {@link Mapper#componentModel()}.
*
* Mapper implementation types are expected to have the same fully qualified name as their interface type, with the
* suffix {@code Impl} appended. When using this factory, mapper types - and any mappers they use - are instantiated by
* invoking their public no-args constructor.
*
* By convention, a single instance of each mapper is retrieved from the factory and exposed on the mapper interface
* type by declaring a member named {@code INSTANCE} like this:
*
*
* @Mapper
* public interface CustomerMapper {
*
* CustomerMapper INSTANCE = Mappers.getMapper( CustomerMapper.class );
*
* // mapping methods...
* }
*
*
* @author Gunnar Morling
*/
public class Mappers {
private static final String IMPLEMENTATION_SUFFIX = "Impl";
private Mappers() {
}
/**
* Returns an instance of the given mapper type.
*
* @param clazz The type of the mapper to return.
* @param The type of the mapper to create.
*
* @return An instance of the given mapper type.
*/
public static T getMapper(Class clazz) {
try {
List classLoaders = collectClassLoaders( clazz.getClassLoader() );
return getMapper( clazz, classLoaders );
}
catch ( ClassNotFoundException | NoSuchMethodException e ) {
throw new RuntimeException( e );
}
}
private static T getMapper(Class mapperType, Iterable classLoaders)
throws ClassNotFoundException, NoSuchMethodException {
for ( ClassLoader classLoader : classLoaders ) {
T mapper = doGetMapper( mapperType, classLoader );
if ( mapper != null ) {
return mapper;
}
}
throw new ClassNotFoundException("Cannot find implementation for " + mapperType.getName() );
}
private static T doGetMapper(Class clazz, ClassLoader classLoader) throws NoSuchMethodException {
try {
@SuppressWarnings( "unchecked" )
Class implementation = (Class) classLoader.loadClass( clazz.getName() + IMPLEMENTATION_SUFFIX );
Constructor constructor = implementation.getDeclaredConstructor();
constructor.setAccessible( true );
return constructor.newInstance();
}
catch (ClassNotFoundException e) {
return getMapperFromServiceLoader( clazz, classLoader );
}
catch ( InstantiationException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException( e );
}
}
/**
* Returns the class of the implementation for the given mapper type.
*
* @param clazz The type of the mapper to return.
* @param The type of the mapper to create.
*
* @return A class of the implementation for the given mapper type.
*
* @since 1.3
*/
public static Class extends T> getMapperClass(Class clazz) {
try {
List classLoaders = collectClassLoaders( clazz.getClassLoader() );
return getMapperClass( clazz, classLoaders );
}
catch ( ClassNotFoundException e ) {
throw new RuntimeException( e );
}
}
private static Class extends T> getMapperClass(Class mapperType, Iterable classLoaders)
throws ClassNotFoundException {
for ( ClassLoader classLoader : classLoaders ) {
Class extends T> mapperClass = doGetMapperClass( mapperType, classLoader );
if ( mapperClass != null ) {
return mapperClass;
}
}
throw new ClassNotFoundException( "Cannot find implementation for " + mapperType.getName() );
}
@SuppressWarnings("unchecked")
private static Class extends T> doGetMapperClass(Class clazz, ClassLoader classLoader) {
try {
return (Class extends T>) classLoader.loadClass( clazz.getName() + IMPLEMENTATION_SUFFIX );
}
catch ( ClassNotFoundException e ) {
T mapper = getMapperFromServiceLoader( clazz, classLoader );
if ( mapper != null ) {
return (Class extends T>) mapper.getClass();
}
return null;
}
}
private static T getMapperFromServiceLoader(Class clazz, ClassLoader classLoader) {
ServiceLoader loader = ServiceLoader.load( clazz, classLoader );
for ( T mapper : loader ) {
if ( mapper != null ) {
return mapper;
}
}
return null;
}
private static List collectClassLoaders(ClassLoader classLoader) {
List classLoaders = new ArrayList<>( 3 );
classLoaders.add( classLoader );
if ( Thread.currentThread().getContextClassLoader() != null ) {
classLoaders.add( Thread.currentThread().getContextClassLoader() );
}
classLoaders.add( Mappers.class.getClassLoader() );
return classLoaders;
}
}