Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions core/src/main/java/org/mapstruct/ClassAccessibility.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct;

/**
* Determines whether a generated Mapper implementation class will be declared {@code public} or not.
*
* @author Raimund Klein
*
* @since 1.7.0
*/
public enum ClassAccessibility {
/**
* The generated Mapper will have the same modifier ({@code public} or none) as the annotated class or interface.
*/
DEFAULT,
/**
* The generated Mapper will be declared {@code public}.
*/
PUBLIC,
/**
* The generated Mapper will have no visibility modifier ("package-private").
*/
PACKAGE_PRIVATE
}
10 changes: 10 additions & 0 deletions core/src/main/java/org/mapstruct/Mapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.mapstruct.control.MappingControl;
import org.mapstruct.factory.Mappers;

import static org.mapstruct.ClassAccessibility.DEFAULT;
import static org.mapstruct.NullValueCheckStrategy.ON_IMPLICIT_CONVERSION;
import static org.mapstruct.SubclassExhaustiveStrategy.COMPILE_ERROR;

Expand Down Expand Up @@ -388,4 +389,13 @@ NullValuePropertyMappingStrategy nullValuePropertyMappingStrategy() default
* @since 1.5
*/
boolean suppressTimestampInGenerated() default false;

/**
* Determines the {@link ClassAccessibility} ({@code public} or package-private) for the generated Mapper
* implementation. Default is to mirror the interface or abstract class annotated by this {@code Mapper}.
*
* @return The {@link ClassAccessibility} ({@code public} or package-private) for the generated Mapper
* implementation
*/
ClassAccessibility accessibility() default DEFAULT;
}
10 changes: 10 additions & 0 deletions core/src/main/java/org/mapstruct/MapperConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.mapstruct.control.MappingControl;
import org.mapstruct.factory.Mappers;

import static org.mapstruct.ClassAccessibility.DEFAULT;
import static org.mapstruct.NullValueCheckStrategy.ON_IMPLICIT_CONVERSION;
import static org.mapstruct.SubclassExhaustiveStrategy.COMPILE_ERROR;

Expand Down Expand Up @@ -357,5 +358,14 @@ MappingInheritanceStrategy mappingInheritanceStrategy()
* @since 1.5
*/
boolean suppressTimestampInGenerated() default false;

/**
* Determines the {@link ClassAccessibility} ({@code public} or package-private) for the generated Mapper
* implementation. Default is to mirror the interface or abstract class annotated by {@code Mapper}.
*
* @return The {@link ClassAccessibility} ({@code public} or package-private) for the generated Mapper
* implementation
*/
ClassAccessibility accessibility() default DEFAULT;
}

Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,24 @@ In that case utilize the `InjectionStrategy#SETTER` strategy.
[TIP]
====
For abstract classes or decorators setter injection should be used.
====
====

[[class-accessibility]]
=== Class accessibility

By default, the generated Mapper implementation will have the same accessibility (`public` or none) as the interface or abstract class carrying the `@Mapper` annotation. Especially in conjunction with a DI framework, this might not be desired. If you wish to reduce the visibility of the generated class, you can make use of the `accessibility` attribute like this:

====
[source, java, linenums]
[subs="verbatim,attributes"]
----
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, accessibility = ClassAccessibility.PACKAGE_PRIVATE)
public interface CarMapper {

CarDto carToCarDto(Car car);
}

----
====

In this case, the generated Mapper will have no modifier. Possible values are `ClassAccessibility.DEFAULT` (the behavior described above), `ClassAccessibility.PUBLIC`, and `ClassAccessibility.PACKAGE_PRIVATE` (no modifier).
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.internal.gem;

/**
* Gem for the enum {@link org.mapstruct.ClassAccessibility}
*
* @author Raimund Klein
*/
public enum ClassAccessibilityGem {
DEFAULT, PUBLIC, PACKAGE_PRIVATE
}
Comment thread
Chessray marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.TreeSet;
import javax.lang.model.type.TypeKind;

import org.mapstruct.ap.internal.gem.ClassAccessibilityGem;
import org.mapstruct.ap.internal.model.common.Accessibility;
import org.mapstruct.ap.internal.model.common.ModelElement;
import org.mapstruct.ap.internal.model.common.Type;
Expand Down Expand Up @@ -40,6 +41,7 @@ protected abstract static class GeneratedTypeBuilder<T extends GeneratedTypeBuil
protected SortedSet<Type> extraImportedTypes;

protected List<MappingMethod> methods;
protected ClassAccessibilityGem classAccessibility;

GeneratedTypeBuilder(Class<T> selfType) {
myself = selfType.cast( this );
Expand Down Expand Up @@ -75,6 +77,10 @@ public T methods(List<MappingMethod> methods) {
return myself;
}

public T classAccessibility(ClassAccessibilityGem classAccessibility) {
this.classAccessibility = classAccessibility;
return myself;
}
}

private final String packageName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import org.mapstruct.ap.internal.option.Options;
import org.mapstruct.ap.internal.version.VersionInformation;

import static org.mapstruct.ap.internal.gem.ClassAccessibilityGem.DEFAULT;

/**
* Represents a type implementing a mapper interface (annotated with {@code @Mapper}). This is the root object of the
* mapper model.
Expand Down Expand Up @@ -109,6 +111,10 @@ public Mapper build() {

Type definitionType = typeFactory.getType( element );

Accessibility accessibility =
classAccessibility == DEFAULT ? Accessibility.fromModifiers( element.getModifiers() ) :
Accessibility.valueOf( classAccessibility.name() );

return new Mapper(
typeFactory,
packageName,
Expand All @@ -121,7 +127,7 @@ public Mapper build() {
options,
versionInformation,
suppressGeneratorTimestamp,
Accessibility.fromModifiers( element.getModifiers() ),
accessibility,
fields,
constructor,
decorator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* @author Andreas Gudian
*/
public enum Accessibility {
PRIVATE( "private" ), DEFAULT( "" ), PROTECTED( "protected" ), PUBLIC( "public" );
PRIVATE( "private" ), PACKAGE_PRIVATE( "" ), PROTECTED( "protected" ), PUBLIC( "public" );

private final String keyword;

Expand All @@ -37,6 +37,6 @@ else if ( modifiers.contains( Modifier.PRIVATE ) ) {
return PRIVATE;
}

return DEFAULT;
return PACKAGE_PRIVATE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import javax.lang.model.type.TypeMirror;

import org.mapstruct.ap.internal.gem.BuilderGem;
import org.mapstruct.ap.internal.gem.ClassAccessibilityGem;
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
import org.mapstruct.ap.internal.gem.InjectionStrategyGem;
import org.mapstruct.ap.internal.gem.MapperGem;
Expand Down Expand Up @@ -155,6 +156,11 @@ public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
return NullValueMappingStrategyGem.valueOf( mapper.nullValueMapMappingStrategy().getDefaultValue() );
}

@Override
public ClassAccessibilityGem accessibility() {
return ClassAccessibilityGem.valueOf( mapper.accessibility().getDefaultValue() );
}

public BuilderGem getBuilder() {
// TODO: I realized this is not correct, however it needs to be null in order to keep downward compatibility
// but assuming a default @Builder will make testcases fail. Not having a default means that you need to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import javax.lang.model.type.TypeMirror;

import org.mapstruct.ap.internal.gem.BuilderGem;
import org.mapstruct.ap.internal.gem.ClassAccessibilityGem;
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
import org.mapstruct.ap.internal.gem.InjectionStrategyGem;
import org.mapstruct.ap.internal.gem.MappingInheritanceStrategyGem;
Expand Down Expand Up @@ -84,6 +85,10 @@ public Boolean isDisableSubMappingMethodsGeneration() {
return next.isDisableSubMappingMethodsGeneration();
}

public ClassAccessibilityGem accessibility() {
return next.accessibility();
}

// BeanMapping and Mapping

public CollectionMappingStrategyGem getCollectionMappingStrategy() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import javax.lang.model.type.TypeMirror;

import org.mapstruct.ap.internal.gem.BuilderGem;
import org.mapstruct.ap.internal.gem.ClassAccessibilityGem;
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
import org.mapstruct.ap.internal.gem.InjectionStrategyGem;
import org.mapstruct.ap.internal.gem.MapperConfigGem;
Expand Down Expand Up @@ -169,6 +170,13 @@ public NullValueMappingStrategyGem getNullValueMapMappingStrategy() {
return next().getNullValueMapMappingStrategy();
}

@Override
public ClassAccessibilityGem accessibility() {
return mapperConfig.accessibility().hasValue() ?
ClassAccessibilityGem.valueOf( mapperConfig.accessibility().get() ) :
next().accessibility();
}

@Override
public BuilderGem getBuilder() {
return mapperConfig.builder().hasValue() ? mapperConfig.builder().get() : next().getBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import javax.lang.model.type.TypeMirror;

import org.mapstruct.ap.internal.gem.BuilderGem;
import org.mapstruct.ap.internal.gem.ClassAccessibilityGem;
import org.mapstruct.ap.internal.gem.CollectionMappingStrategyGem;
import org.mapstruct.ap.internal.gem.InjectionStrategyGem;
import org.mapstruct.ap.internal.gem.MapperConfigGem;
Expand Down Expand Up @@ -170,6 +171,13 @@ public SubclassExhaustiveStrategyGem getSubclassExhaustiveStrategy() {
next().getSubclassExhaustiveStrategy();
}

@Override
public ClassAccessibilityGem accessibility() {
return mapper.accessibility().hasValue() ?
ClassAccessibilityGem.valueOf( mapper.accessibility().get() ) :
next().accessibility();
}

@Override
public TypeMirror getSubclassExhaustiveException() {
return mapper.subclassExhaustiveException().hasValue() ?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ private Mapper getMapper(TypeElement element, MapperOptions mapperOptions, List<
.suppressGeneratorTimestamp( mapperOptions.suppressTimestampInGenerated() )
.additionalAnnotations( additionalAnnotationsBuilder.getProcessedAnnotations( element ) )
.javadoc( getJavadoc( element ) )
.classAccessibility( mapperOptions.accessibility() )
.build();

if ( !mappingContext.getForgedMethodsUnderCreation().isEmpty() ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.classaccessibility;

import org.mapstruct.ap.testutil.ProcessorTest;
import org.mapstruct.ap.testutil.WithClasses;

import static java.lang.reflect.Modifier.isPrivate;
import static java.lang.reflect.Modifier.isProtected;
import static java.lang.reflect.Modifier.isPublic;
import static org.assertj.core.api.Assertions.assertThat;

@WithClasses({
Source.class,
Target.class,
PublicAbstractionMapper.class,
PackageAbstractionMapper.class,
ForcedPublicMapper.class,
ForcedPackagePrivateMapper.class
})
public class ClassAccessibilityTest {

@ProcessorTest
public void shouldCreateModifierAccordingToAnnotation() throws Exception {
Class<?> publicLike = loadForMapper( PublicAbstractionMapper.class );
assertThat( isPublic( publicLike.getModifiers() ) ).isTrue();

Class<?> packageLike = loadForMapper( PackageAbstractionMapper.class );
assertThat( isDefault( packageLike.getModifiers() ) ).isTrue();

Class<?> forcedPublic = loadForMapper( ForcedPublicMapper.class );
assertThat( isPublic( forcedPublic.getModifiers() ) ).isTrue();

Class<?> forcedDefault = loadForMapper( ForcedPackagePrivateMapper.class );
assertThat( isDefault( forcedDefault.getModifiers() ) ).isTrue();
}

private static Class<?> loadForMapper(Class<?> mapper) throws ClassNotFoundException {
return Thread.currentThread().getContextClassLoader().loadClass( mapper.getName() + "Impl" );
}

private static boolean isDefault(int modifiers) {
return !isPublic( modifiers ) && !isProtected( modifiers ) && !isPrivate( modifiers );
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.classaccessibility;

import org.mapstruct.ClassAccessibility;
import org.mapstruct.Mapper;

@Mapper(accessibility = ClassAccessibility.PACKAGE_PRIVATE)
public interface ForcedPackagePrivateMapper {
Target map(Source value);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.classaccessibility;

import org.mapstruct.ClassAccessibility;
import org.mapstruct.Mapper;

@Mapper(accessibility = ClassAccessibility.PUBLIC)
interface ForcedPublicMapper {
Target map(Source value);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.classaccessibility;

import org.mapstruct.Mapper;

@Mapper
interface PackageAbstractionMapper {
Target map(Source value);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright MapStruct Authors.
*
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
*/
package org.mapstruct.ap.test.classaccessibility;

import org.mapstruct.Mapper;

@Mapper
public interface PublicAbstractionMapper {
Target map(Source value);
}

Loading
Loading