mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#365 Making Services factory agnostic of specific services
This commit is contained in:
parent
3ba4ded58c
commit
77298c750e
@ -20,12 +20,10 @@ package org.mapstruct.ap.model.assignment;
|
|||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
|
|
||||||
import org.mapstruct.ap.model.common.Type;
|
import org.mapstruct.ap.model.common.Type;
|
||||||
import org.mapstruct.ap.services.Services;
|
import org.mapstruct.ap.util.Executables;
|
||||||
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This wrapper handles the situation were an assignment is done via the setter.
|
* This wrapper handles the situation were an assignment is done via the setter.
|
||||||
@ -45,15 +43,11 @@ public class SetterWrapperForCollectionsAndMaps extends AssignmentWrapper {
|
|||||||
private final Assignment newCollectionOrMapAssignment;
|
private final Assignment newCollectionOrMapAssignment;
|
||||||
|
|
||||||
public SetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment,
|
public SetterWrapperForCollectionsAndMaps(Assignment decoratedAssignment,
|
||||||
ExecutableElement targetSetter,
|
ExecutableElement targetSetter,
|
||||||
Assignment newCollectionOrMapAssignment) {
|
Assignment newCollectionOrMapAssignment) {
|
||||||
super( decoratedAssignment );
|
super( decoratedAssignment );
|
||||||
|
|
||||||
AccessorNamingStrategy accessorNamingStrategy = Services.getAccessorNamingStrategy();
|
this.targetGetterName = Executables.getCollectionGetterName( targetSetter );
|
||||||
|
|
||||||
this.targetGetterName = accessorNamingStrategy.getCollectionGetterName(
|
|
||||||
accessorNamingStrategy.getPropertyName( targetSetter )
|
|
||||||
);
|
|
||||||
this.newCollectionOrMapAssignment = newCollectionOrMapAssignment;
|
this.newCollectionOrMapAssignment = newCollectionOrMapAssignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,10 +16,9 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.mapstruct.ap.services;
|
package org.mapstruct.ap.naming;
|
||||||
|
|
||||||
import java.beans.Introspector;
|
import java.beans.Introspector;
|
||||||
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
import javax.lang.model.type.DeclaredType;
|
import javax.lang.model.type.DeclaredType;
|
||||||
@ -36,7 +35,7 @@ import org.mapstruct.ap.spi.MethodType;
|
|||||||
*
|
*
|
||||||
* @author Christian Schuster
|
* @author Christian Schuster
|
||||||
*/
|
*/
|
||||||
class DefaultAccessorNamingStrategy implements AccessorNamingStrategy {
|
public class DefaultAccessorNamingStrategy implements AccessorNamingStrategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodType getMethodType(ExecutableElement method) {
|
public MethodType getMethodType(ExecutableElement method) {
|
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||||
|
* and/or other contributors as indicated by the @authors tag. See the
|
||||||
|
* copyright.txt file in the distribution for a full listing of all
|
||||||
|
* contributors.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* SPI (service provider interface) contracts to be implemented for advanced use cases.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
package org.mapstruct.ap.naming;
|
@ -19,8 +19,8 @@
|
|||||||
package org.mapstruct.ap.services;
|
package org.mapstruct.ap.services;
|
||||||
|
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple locator for SPI implementations.
|
* A simple locator for SPI implementations.
|
||||||
@ -29,32 +29,35 @@ import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
|||||||
*/
|
*/
|
||||||
public class Services {
|
public class Services {
|
||||||
|
|
||||||
private static final AccessorNamingStrategy ACCESSOR_NAMING_STRATEGY = findAccessorNamingStrategy();
|
private static final ConcurrentMap<Class<?>, Object> SERVICES = new ConcurrentHashMap<Class<?>, Object>();
|
||||||
|
|
||||||
private Services() {
|
private Services() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static <T> T get(Class<T> serviceType, T defaultValue) {
|
||||||
* Obtain an implementation of {@link AccessorNamingStrategy}. If no specialized implementation is found using
|
@SuppressWarnings("unchecked")
|
||||||
* {@link ServiceLoader}, a JavaBeans-compliant default implementation is returned. The result is cached across
|
T service = (T) SERVICES.get( serviceType );
|
||||||
* invocations.
|
|
||||||
*
|
|
||||||
* @return The implementation of {@link AccessorNamingStrategy}.
|
|
||||||
* @throws IllegalStateException If more than one implementation is found by
|
|
||||||
* {@link ServiceLoader#load(Class, ClassLoader)}.
|
|
||||||
*/
|
|
||||||
public static AccessorNamingStrategy getAccessorNamingStrategy() {
|
|
||||||
return ACCESSOR_NAMING_STRATEGY;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AccessorNamingStrategy findAccessorNamingStrategy() {
|
if ( service == null ) {
|
||||||
AccessorNamingStrategy defaultImpl = new DefaultAccessorNamingStrategy();
|
service = loadAndCache( serviceType, defaultValue );
|
||||||
AccessorNamingStrategy impl = find( AccessorNamingStrategy.class );
|
|
||||||
if ( impl == null ) {
|
|
||||||
impl = defaultImpl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return impl;
|
return service;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T> T loadAndCache(Class<T> serviceType, T defaultValue) {
|
||||||
|
T service = find( serviceType );
|
||||||
|
if ( service == null ) {
|
||||||
|
service = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
T cached = (T) SERVICES.putIfAbsent( serviceType, service );
|
||||||
|
if ( cached != null ) {
|
||||||
|
service = (T) cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> T find(Class<T> spi) {
|
private static <T> T find(Class<T> spi) {
|
||||||
@ -68,7 +71,8 @@ public class Services {
|
|||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Multiple implementations have been found for the service provider interface "
|
"Multiple implementations have been found for the service provider interface "
|
||||||
+ spi.getCanonicalName() + ": " + matchingImplementation.getClass().getCanonicalName() + ", "
|
+ spi.getCanonicalName() + ": " + matchingImplementation.getClass().getCanonicalName() + ", "
|
||||||
+ implementation.getClass().getCanonicalName() + "." );
|
+ implementation.getClass().getCanonicalName() + "."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ package org.mapstruct.ap.util;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.lang.model.element.ExecutableElement;
|
import javax.lang.model.element.ExecutableElement;
|
||||||
import javax.lang.model.element.Modifier;
|
import javax.lang.model.element.Modifier;
|
||||||
import javax.lang.model.element.TypeElement;
|
import javax.lang.model.element.TypeElement;
|
||||||
@ -29,6 +28,7 @@ import javax.lang.model.type.TypeKind;
|
|||||||
import javax.lang.model.type.TypeMirror;
|
import javax.lang.model.type.TypeMirror;
|
||||||
import javax.lang.model.util.Elements;
|
import javax.lang.model.util.Elements;
|
||||||
|
|
||||||
|
import org.mapstruct.ap.naming.DefaultAccessorNamingStrategy;
|
||||||
import org.mapstruct.ap.services.Services;
|
import org.mapstruct.ap.services.Services;
|
||||||
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
import org.mapstruct.ap.spi.AccessorNamingStrategy;
|
||||||
import org.mapstruct.ap.spi.MethodType;
|
import org.mapstruct.ap.spi.MethodType;
|
||||||
@ -43,7 +43,10 @@ import static org.mapstruct.ap.util.SpecificCompilerWorkarounds.replaceTypeEleme
|
|||||||
*/
|
*/
|
||||||
public class Executables {
|
public class Executables {
|
||||||
|
|
||||||
private static AccessorNamingStrategy accessorNamingStrategy = Services.getAccessorNamingStrategy();
|
private static AccessorNamingStrategy accessorNamingStrategy = Services.get(
|
||||||
|
AccessorNamingStrategy.class,
|
||||||
|
new DefaultAccessorNamingStrategy()
|
||||||
|
);
|
||||||
|
|
||||||
private Executables() {
|
private Executables() {
|
||||||
}
|
}
|
||||||
@ -51,7 +54,7 @@ public class Executables {
|
|||||||
public static boolean isGetterMethod(ExecutableElement method) {
|
public static boolean isGetterMethod(ExecutableElement method) {
|
||||||
return isPublic( method ) &&
|
return isPublic( method ) &&
|
||||||
method.getParameters().isEmpty() &&
|
method.getParameters().isEmpty() &&
|
||||||
Services.getAccessorNamingStrategy().getMethodType( method ) == MethodType.GETTER;
|
accessorNamingStrategy.getMethodType( method ) == MethodType.GETTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSetterMethod(ExecutableElement method) {
|
public static boolean isSetterMethod(ExecutableElement method) {
|
||||||
@ -83,6 +86,11 @@ public class Executables {
|
|||||||
return accessorNamingStrategy.getElementName( adderMethod );
|
return accessorNamingStrategy.getElementName( adderMethod );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getCollectionGetterName(ExecutableElement targetSetter) {
|
||||||
|
String propertyName = accessorNamingStrategy.getPropertyName( targetSetter );
|
||||||
|
return accessorNamingStrategy.getCollectionGetterName( propertyName );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param mirror the type mirror
|
* @param mirror the type mirror
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user