mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#3331 Do not handle defined mappings if the result type is abstract due to runtime exception subclass exhaustive strategy (#3487)
This commit is contained in:
parent
8191c850e0
commit
ca1fd0d85d
@ -284,10 +284,15 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
|
||||
initializeMappingReferencesIfNeeded( resultTypeToMap );
|
||||
|
||||
// map properties with mapping
|
||||
boolean mappingErrorOccurred = handleDefinedMappings( resultTypeToMap );
|
||||
if ( mappingErrorOccurred ) {
|
||||
return null;
|
||||
boolean shouldHandledDefinedMappings = shouldHandledDefinedMappings( resultTypeToMap );
|
||||
|
||||
|
||||
if ( shouldHandledDefinedMappings ) {
|
||||
// map properties with mapping
|
||||
boolean mappingErrorOccurred = handleDefinedMappings( resultTypeToMap );
|
||||
if ( mappingErrorOccurred ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
boolean applyImplicitMappings = !mappingReferences.isRestrictToDefinedMappings();
|
||||
@ -1045,6 +1050,36 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
return (List<AnnotationValue>) av.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether defined mappings should be handled on the result type.
|
||||
* They should be, if any of the following is true:
|
||||
* <ul>
|
||||
* <li>The {@code resultTypeToMap} is not abstract</li>
|
||||
* <li>There is a factory method</li>
|
||||
* <li>The method is an update method</li>
|
||||
* </ul>
|
||||
* Otherwise, it means that we have reached this because subclass mappings are being used
|
||||
* and the chosen strategy is runtime exception.
|
||||
*
|
||||
* @param resultTypeToMap the type in which the defined target properties are defined
|
||||
* @return {@code true} if defined mappings should be handled for the result type, {@code false} otherwise
|
||||
*/
|
||||
private boolean shouldHandledDefinedMappings(Type resultTypeToMap) {
|
||||
if ( !resultTypeToMap.isAbstract() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( hasFactoryMethod ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( method.isUpdateMethod() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all defined mapping methods ({@code @Mapping(s)}), either directly given or inherited from the
|
||||
* inverse mapping method.
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.bugs._3331;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.SubclassExhaustiveStrategy;
|
||||
import org.mapstruct.SubclassMapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@Mapper(subclassExhaustiveStrategy = SubclassExhaustiveStrategy.RUNTIME_EXCEPTION)
|
||||
public interface Issue3331Mapper {
|
||||
|
||||
Issue3331Mapper INSTANCE = Mappers.getMapper( Issue3331Mapper.class );
|
||||
|
||||
@SubclassMapping(source = Vehicle.Car.class, target = VehicleDto.Car.class)
|
||||
@SubclassMapping(source = Vehicle.Motorbike.class, target = VehicleDto.Motorbike.class)
|
||||
@Mapping(target = "name", constant = "noname")
|
||||
VehicleDto map(Vehicle vehicle);
|
||||
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.bugs._3331;
|
||||
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.ProcessorTest;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
@IssueKey("3331")
|
||||
@WithClasses({
|
||||
Issue3331Mapper.class,
|
||||
Vehicle.class,
|
||||
VehicleDto.class,
|
||||
})
|
||||
class Issue3331Test {
|
||||
|
||||
@ProcessorTest
|
||||
void shouldCorrectCompileAndThrowExceptionOnRuntime() {
|
||||
VehicleDto target = Issue3331Mapper.INSTANCE.map( new Vehicle.Car( "Test car", 4 ) );
|
||||
|
||||
assertThat( target.getName() ).isEqualTo( "noname" );
|
||||
assertThat( target )
|
||||
.isInstanceOfSatisfying( VehicleDto.Car.class, car -> {
|
||||
assertThat( car.getNumOfDoors() ).isEqualTo( 4 );
|
||||
} );
|
||||
|
||||
target = Issue3331Mapper.INSTANCE.map( new Vehicle.Motorbike( "Test bike", true ) );
|
||||
|
||||
assertThat( target.getName() ).isEqualTo( "noname" );
|
||||
assertThat( target )
|
||||
.isInstanceOfSatisfying( VehicleDto.Motorbike.class, bike -> {
|
||||
assertThat( bike.isAllowedForMinor() ).isTrue();
|
||||
} );
|
||||
|
||||
assertThatThrownBy( () -> Issue3331Mapper.INSTANCE.map( new Vehicle.Truck( "Test truck", 3 ) ) )
|
||||
.isInstanceOf( IllegalArgumentException.class )
|
||||
.hasMessage( "Not all subclasses are supported for this mapping. Missing for " + Vehicle.Truck.class );
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.bugs._3331;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public abstract class Vehicle {
|
||||
|
||||
private final String name;
|
||||
|
||||
protected Vehicle(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static class Car extends Vehicle {
|
||||
|
||||
private final int numOfDoors;
|
||||
|
||||
public Car(String name, int numOfDoors) {
|
||||
super( name );
|
||||
this.numOfDoors = numOfDoors;
|
||||
}
|
||||
|
||||
public int getNumOfDoors() {
|
||||
return numOfDoors;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Motorbike extends Vehicle {
|
||||
|
||||
private final boolean allowedForMinor;
|
||||
|
||||
public Motorbike(String name, boolean allowedForMinor) {
|
||||
super( name );
|
||||
this.allowedForMinor = allowedForMinor;
|
||||
}
|
||||
|
||||
public boolean isAllowedForMinor() {
|
||||
return allowedForMinor;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Truck extends Vehicle {
|
||||
|
||||
private final int numOfAxis;
|
||||
|
||||
public Truck(String name, int numOfAxis) {
|
||||
super( name );
|
||||
this.numOfAxis = numOfAxis;
|
||||
}
|
||||
|
||||
public int getNumOfAxis() {
|
||||
return numOfAxis;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.bugs._3331;
|
||||
|
||||
/**
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public abstract class VehicleDto {
|
||||
|
||||
private final String name;
|
||||
|
||||
protected VehicleDto(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static class Car extends VehicleDto {
|
||||
|
||||
private final int numOfDoors;
|
||||
|
||||
public Car(String name, int numOfDoors) {
|
||||
super( name );
|
||||
this.numOfDoors = numOfDoors;
|
||||
}
|
||||
|
||||
public int getNumOfDoors() {
|
||||
return numOfDoors;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Motorbike extends VehicleDto {
|
||||
|
||||
private final boolean allowedForMinor;
|
||||
|
||||
public Motorbike(String name, boolean allowedForMinor) {
|
||||
super( name );
|
||||
this.allowedForMinor = allowedForMinor;
|
||||
}
|
||||
|
||||
public boolean isAllowedForMinor() {
|
||||
return allowedForMinor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user