From 0e33ad4bbcfd7f8628f63221db4faa7415ac4384 Mon Sep 17 00:00:00 2001 From: Christian Bandowski Date: Sat, 22 Dec 2018 15:19:39 +0100 Subject: [PATCH] #1657 Add Mappers.getMapperClass for getting the class of a Mapper --- .../java/org/mapstruct/factory/Mappers.java | 96 +++++++++++++++---- .../org/mapstruct/factory/MappersTest.java | 21 +++- 2 files changed, 97 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/org/mapstruct/factory/Mappers.java b/core/src/main/java/org/mapstruct/factory/Mappers.java index ac479d364..05b616fe9 100644 --- a/core/src/main/java/org/mapstruct/factory/Mappers.java +++ b/core/src/main/java/org/mapstruct/factory/Mappers.java @@ -53,14 +53,7 @@ public class Mappers { */ public static T getMapper(Class clazz) { try { - List classLoaders = new ArrayList<>( 3 ); - classLoaders.add( clazz.getClassLoader() ); - - if ( Thread.currentThread().getContextClassLoader() != null ) { - classLoaders.add( Thread.currentThread().getContextClassLoader() ); - } - - classLoaders.add( Mappers.class.getClassLoader() ); + List classLoaders = collectClassLoaders( clazz.getClassLoader() ); return getMapper( clazz, classLoaders ); } @@ -88,23 +81,88 @@ public class Mappers { Class implementation = (Class) classLoader.loadClass( clazz.getName() + IMPLEMENTATION_SUFFIX ); Constructor constructor = implementation.getDeclaredConstructor(); constructor.setAccessible( true ); + return constructor.newInstance(); } catch (ClassNotFoundException e) { - ServiceLoader loader = ServiceLoader.load( clazz, classLoader ); - - if ( loader != null ) { - for ( T mapper : loader ) { - if ( mapper != null ) { - return mapper; - } - } - } - - return null; + 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 getMapperClass(Class clazz) { + try { + List classLoaders = collectClassLoaders( clazz.getClassLoader() ); + + return getMapperClass( clazz, classLoaders ); + } + catch ( ClassNotFoundException e ) { + throw new RuntimeException( e ); + } + } + + private static Class getMapperClass(Class mapperType, Iterable classLoaders) + throws ClassNotFoundException { + + for ( ClassLoader classLoader : classLoaders ) { + Class mapperClass = doGetMapperClass( mapperType, classLoader ); + if ( mapperClass != null ) { + return mapperClass; + } + } + + throw new ClassNotFoundException( "Cannot find implementation for " + mapperType.getName() ); + } + + @SuppressWarnings("unchecked") + private static Class doGetMapperClass(Class clazz, ClassLoader classLoader) { + try { + return (Class) classLoader.loadClass( clazz.getName() + IMPLEMENTATION_SUFFIX ); + } + catch ( ClassNotFoundException e ) { + T mapper = getMapperFromServiceLoader( clazz, classLoader ); + if ( mapper != null ) { + return (Class) 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; + } } diff --git a/core/src/test/java/org/mapstruct/factory/MappersTest.java b/core/src/test/java/org/mapstruct/factory/MappersTest.java index 507eb08d0..60371cada 100644 --- a/core/src/test/java/org/mapstruct/factory/MappersTest.java +++ b/core/src/test/java/org/mapstruct/factory/MappersTest.java @@ -25,18 +25,37 @@ public class MappersTest { assertThat( mapper ).isNotNull(); } + @Test + public void shouldReturnImplementationClass() { + + Class mapperClass = Mappers.getMapperClass( Foo.class ); + assertThat( mapperClass ).isNotNull(); + assertThat( mapperClass ).isNotExactlyInstanceOf( Foo.class ); + } + /** * Checks if an implementation of a nested mapper can be found. This is a special case since * it is named */ @Test - public void findsNestedMapperImpl() throws Exception { + public void findsNestedMapperImpl() { assertThat( Mappers.getMapper( SomeClass.Foo.class ) ).isNotNull(); assertThat( Mappers.getMapper( SomeClass.NestedClass.Foo.class ) ).isNotNull(); } + @Test + public void findsNestedMapperImplClass() { + assertThat( Mappers.getMapperClass( SomeClass.Foo.class ) ).isNotNull(); + assertThat( Mappers.getMapperClass( SomeClass.NestedClass.Foo.class ) ).isNotNull(); + } + @Test public void shouldReturnPackagePrivateImplementationInstance() { assertThat( Mappers.getMapper( PackagePrivateMapper.class ) ).isNotNull(); } + + @Test + public void shouldReturnPackagePrivateImplementationClass() { + assertThat( Mappers.getMapperClass( PackagePrivateMapper.class ) ).isNotNull(); + } }