mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#3054: Allow abstract return type when all directly sealed subtypes are covered by subclass mappings
Co-authored-by: Ben Zegveld <Ben.Zegveld@gmail.com>
This commit is contained in:
parent
be94569791
commit
bc5a877121
@ -112,6 +112,11 @@ public class MavenIntegrationTest {
|
||||
void protobufBuilderTest() {
|
||||
}
|
||||
|
||||
@ProcessorTest(baseDir = "sealedSubclassTest")
|
||||
@EnabledForJreRange(min = JRE.JAVA_17)
|
||||
void sealedSubclassTest() {
|
||||
}
|
||||
|
||||
@ProcessorTest(baseDir = "recordsTest", processorTypes = {
|
||||
ProcessorTest.ProcessorType.JAVAC
|
||||
})
|
||||
|
102
integrationtest/src/test/resources/sealedSubclassTest/pom.xml
Normal file
102
integrationtest/src/test/resources/sealedSubclassTest/pom.xml
Normal file
@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright MapStruct Authors.
|
||||
|
||||
Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-it-parent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>sealedSubclassTest</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>generate-via-compiler-plugin</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgument
|
||||
combine.self="override"></compilerArgument>
|
||||
<compilerId>\${compiler-id}</compilerId>
|
||||
<compilerArgs>--enable-preview</compilerArgs>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-jdt</artifactId>
|
||||
<version>${org.eclipse.tycho.compiler-jdt.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
<version>${mapstruct.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>debug-forked-javac</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-compile</id>
|
||||
<configuration>
|
||||
<fork>true</fork>
|
||||
<compilerArgs>
|
||||
<arg>--enable-preview</arg>
|
||||
<arg>-J-Xdebug</arg>
|
||||
<arg>-J-Xnoagent</arg>
|
||||
<arg>-J-Djava.compiler=NONE</arg>
|
||||
<arg>-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<forkCount>1</forkCount>
|
||||
<argLine>--enable-preview</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public final class Bike extends Vehicle {
|
||||
private int numberOfGears;
|
||||
|
||||
public int getNumberOfGears() {
|
||||
return numberOfGears;
|
||||
}
|
||||
|
||||
public void setNumberOfGears(int numberOfGears) {
|
||||
this.numberOfGears = numberOfGears;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public final class BikeDto extends VehicleDto {
|
||||
private int numberOfGears;
|
||||
|
||||
public int getNumberOfGears() {
|
||||
return numberOfGears;
|
||||
}
|
||||
|
||||
public void setNumberOfGears(int numberOfGears) {
|
||||
this.numberOfGears = numberOfGears;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public final class Car extends Vehicle {
|
||||
private boolean manual;
|
||||
|
||||
public boolean isManual() {
|
||||
return manual;
|
||||
}
|
||||
|
||||
public void setManual(boolean manual) {
|
||||
this.manual = manual;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public final class CarDto extends VehicleDto {
|
||||
private boolean manual;
|
||||
|
||||
public boolean isManual() {
|
||||
return manual;
|
||||
}
|
||||
|
||||
public void setManual(boolean manual) {
|
||||
this.manual = manual;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public final class Davidson extends Motor {
|
||||
private int numberOfExhausts;
|
||||
|
||||
public int getNumberOfExhausts() {
|
||||
return numberOfExhausts;
|
||||
}
|
||||
|
||||
public void setNumberOfExhausts(int numberOfExhausts) {
|
||||
this.numberOfExhausts = numberOfExhausts;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public final class DavidsonDto extends MotorDto {
|
||||
private int numberOfExhausts;
|
||||
|
||||
public int getNumberOfExhausts() {
|
||||
return numberOfExhausts;
|
||||
}
|
||||
|
||||
public void setNumberOfExhausts(int numberOfExhausts) {
|
||||
this.numberOfExhausts = numberOfExhausts;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public final class Harley extends Motor {
|
||||
private int engineDb;
|
||||
|
||||
public int getEngineDb() {
|
||||
return engineDb;
|
||||
}
|
||||
|
||||
public void setEngineDb(int engineDb) {
|
||||
this.engineDb = engineDb;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public final class HarleyDto extends MotorDto {
|
||||
private int engineDb;
|
||||
|
||||
public int getEngineDb() {
|
||||
return engineDb;
|
||||
}
|
||||
|
||||
public void setEngineDb(int engineDb) {
|
||||
this.engineDb = engineDb;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public sealed abstract class Motor extends Vehicle permits Harley, Davidson {
|
||||
private int cc;
|
||||
|
||||
public int getCc() {
|
||||
return cc;
|
||||
}
|
||||
|
||||
public void setCc(int cc) {
|
||||
this.cc = cc;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
public sealed abstract class MotorDto extends VehicleDto permits HarleyDto, DavidsonDto {
|
||||
private int cc;
|
||||
|
||||
public int getCc() {
|
||||
return cc;
|
||||
}
|
||||
|
||||
public void setCc(int cc) {
|
||||
this.cc = cc;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
import org.mapstruct.InheritInverseConfiguration;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.SubclassMapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
@Mapper
|
||||
public interface SealedSubclassMapper {
|
||||
SealedSubclassMapper INSTANCE = Mappers.getMapper( SealedSubclassMapper.class );
|
||||
|
||||
VehicleCollectionDto map(VehicleCollection vehicles);
|
||||
|
||||
@SubclassMapping( source = Car.class, target = CarDto.class )
|
||||
@SubclassMapping( source = Bike.class, target = BikeDto.class )
|
||||
@SubclassMapping( source = Harley.class, target = HarleyDto.class )
|
||||
@SubclassMapping( source = Davidson.class, target = DavidsonDto.class )
|
||||
@Mapping( source = "vehicleManufacturingCompany", target = "maker")
|
||||
VehicleDto map(Vehicle vehicle);
|
||||
|
||||
VehicleCollection mapInverse(VehicleCollectionDto vehicles);
|
||||
|
||||
@InheritInverseConfiguration
|
||||
Vehicle mapInverse(VehicleDto dto);
|
||||
}
|
@ -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.itest.sealedsubclass;
|
||||
|
||||
public abstract sealed class Vehicle permits Bike, Car, Motor {
|
||||
private String name;
|
||||
private String vehicleManufacturingCompany;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVehicleManufacturingCompany() {
|
||||
return vehicleManufacturingCompany;
|
||||
}
|
||||
|
||||
public void setVehicleManufacturingCompany(String vehicleManufacturingCompany) {
|
||||
this.vehicleManufacturingCompany = vehicleManufacturingCompany;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class VehicleCollection {
|
||||
private Collection<Vehicle> vehicles = new ArrayList<>();
|
||||
|
||||
public Collection<Vehicle> getVehicles() {
|
||||
return vehicles;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class VehicleCollectionDto {
|
||||
private Collection<VehicleDto> vehicles = new ArrayList<>();
|
||||
|
||||
public Collection<VehicleDto> getVehicles() {
|
||||
return vehicles;
|
||||
}
|
||||
}
|
@ -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.itest.sealedsubclass;
|
||||
|
||||
public abstract sealed class VehicleDto permits CarDto, BikeDto, MotorDto {
|
||||
private String name;
|
||||
private String maker;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getMaker() {
|
||||
return maker;
|
||||
}
|
||||
|
||||
public void setMaker(String maker) {
|
||||
this.maker = maker;
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright MapStruct Authors.
|
||||
*
|
||||
* Licensed under the Apache License version 2.0, available at http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
package org.mapstruct.itest.sealedsubclass;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class SealedSubclassTest {
|
||||
|
||||
@Test
|
||||
public void mappingIsDoneUsingSubclassMapping() {
|
||||
VehicleCollection vehicles = new VehicleCollection();
|
||||
vehicles.getVehicles().add( new Car() );
|
||||
vehicles.getVehicles().add( new Bike() );
|
||||
vehicles.getVehicles().add( new Harley() );
|
||||
vehicles.getVehicles().add( new Davidson() );
|
||||
|
||||
VehicleCollectionDto result = SealedSubclassMapper.INSTANCE.map( vehicles );
|
||||
|
||||
assertThat( result.getVehicles() ).doesNotContainNull();
|
||||
assertThat( result.getVehicles() ) // remove generic so that test works.
|
||||
.extracting( vehicle -> (Class) vehicle.getClass() )
|
||||
.containsExactly( CarDto.class, BikeDto.class, HarleyDto.class, DavidsonDto.class );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inverseMappingIsDoneUsingSubclassMapping() {
|
||||
VehicleCollectionDto vehicles = new VehicleCollectionDto();
|
||||
vehicles.getVehicles().add( new CarDto() );
|
||||
vehicles.getVehicles().add( new BikeDto() );
|
||||
vehicles.getVehicles().add( new HarleyDto() );
|
||||
vehicles.getVehicles().add( new DavidsonDto() );
|
||||
|
||||
VehicleCollection result = SealedSubclassMapper.INSTANCE.mapInverse( vehicles );
|
||||
|
||||
assertThat( result.getVehicles() ).doesNotContainNull();
|
||||
assertThat( result.getVehicles() ) // remove generic so that test works.
|
||||
.extracting( vehicle -> (Class) vehicle.getClass() )
|
||||
.containsExactly( Car.class, Bike.class, Harley.class, Davidson.class );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subclassMappingInheritsInverseMapping() {
|
||||
VehicleCollectionDto vehiclesDto = new VehicleCollectionDto();
|
||||
CarDto carDto = new CarDto();
|
||||
carDto.setMaker( "BenZ" );
|
||||
vehiclesDto.getVehicles().add( carDto );
|
||||
|
||||
VehicleCollection result = SealedSubclassMapper.INSTANCE.mapInverse( vehiclesDto );
|
||||
|
||||
assertThat( result.getVehicles() )
|
||||
.extracting( Vehicle::getVehicleManufacturingCompany )
|
||||
.containsExactly( "BenZ" );
|
||||
}
|
||||
}
|
@ -446,8 +446,39 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
}
|
||||
|
||||
private boolean isAbstractReturnTypeAllowed() {
|
||||
return method.getOptions().getBeanMapping().getSubclassExhaustiveStrategy().isAbstractReturnTypeAllowed()
|
||||
&& !method.getOptions().getSubclassMappings().isEmpty();
|
||||
return !method.getOptions().getSubclassMappings().isEmpty()
|
||||
&& ( method.getOptions().getBeanMapping().getSubclassExhaustiveStrategy().isAbstractReturnTypeAllowed()
|
||||
|| isCorrectlySealed() );
|
||||
}
|
||||
|
||||
private boolean isCorrectlySealed() {
|
||||
Type mappingSourceType = method.getMappingSourceType();
|
||||
return isCorrectlySealed( mappingSourceType );
|
||||
}
|
||||
|
||||
private boolean isCorrectlySealed(Type mappingSourceType) {
|
||||
if ( mappingSourceType.isSealed() ) {
|
||||
List<? extends TypeMirror> unusedPermittedSubclasses =
|
||||
new ArrayList<>( mappingSourceType.getPermittedSubclasses() );
|
||||
method.getOptions().getSubclassMappings().forEach( subClassOption -> {
|
||||
for (Iterator<? extends TypeMirror> iterator = unusedPermittedSubclasses.iterator();
|
||||
iterator.hasNext(); ) {
|
||||
if ( ctx.getTypeUtils().isSameType( iterator.next(), subClassOption.getSource() ) ) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
} );
|
||||
for ( Iterator<? extends TypeMirror> iterator = unusedPermittedSubclasses.iterator();
|
||||
iterator.hasNext(); ) {
|
||||
TypeMirror typeMirror = iterator.next();
|
||||
Type type = ctx.getTypeFactory().getType( typeMirror );
|
||||
if ( type.isAbstract() && isCorrectlySealed( type ) ) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return unusedPermittedSubclasses.isEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void initializeMappingReferencesIfNeeded(Type resultTypeToMap) {
|
||||
|
@ -5,6 +5,8 @@
|
||||
*/
|
||||
package org.mapstruct.ap.internal.model.common;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -53,6 +55,7 @@ import org.mapstruct.ap.internal.util.accessor.MapValueAccessor;
|
||||
import org.mapstruct.ap.internal.util.accessor.PresenceCheckAccessor;
|
||||
import org.mapstruct.ap.internal.util.accessor.ReadAccessor;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static org.mapstruct.ap.internal.util.Collections.first;
|
||||
|
||||
/**
|
||||
@ -67,6 +70,18 @@ import static org.mapstruct.ap.internal.util.Collections.first;
|
||||
* @author Filip Hrisafov
|
||||
*/
|
||||
public class Type extends ModelElement implements Comparable<Type> {
|
||||
private static final Method SEALED_PERMITTED_SUBCLASSES_METHOD;
|
||||
|
||||
static {
|
||||
Method permittedSubclassesMethod;
|
||||
try {
|
||||
permittedSubclassesMethod = TypeElement.class.getMethod( "getPermittedSubclasses" );
|
||||
}
|
||||
catch ( NoSuchMethodException e ) {
|
||||
permittedSubclassesMethod = null;
|
||||
}
|
||||
SEALED_PERMITTED_SUBCLASSES_METHOD = permittedSubclassesMethod;
|
||||
}
|
||||
|
||||
private final TypeUtils typeUtils;
|
||||
private final ElementUtils elementUtils;
|
||||
@ -1661,4 +1676,27 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
return "java.util.EnumSet".equals( getFullyQualifiedName() );
|
||||
}
|
||||
|
||||
/**
|
||||
* return true if this type is a java 17+ sealed class
|
||||
*/
|
||||
public boolean isSealed() {
|
||||
return typeElement.getModifiers().stream().map( Modifier::name ).anyMatch( "SEALED"::equals );
|
||||
}
|
||||
|
||||
/**
|
||||
* return the list of permitted TypeMirrors for the java 17+ sealed class
|
||||
*/
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public List<? extends TypeMirror> getPermittedSubclasses() {
|
||||
if (SEALED_PERMITTED_SUBCLASSES_METHOD == null) {
|
||||
return emptyList();
|
||||
}
|
||||
try {
|
||||
return (List<? extends TypeMirror>) SEALED_PERMITTED_SUBCLASSES_METHOD.invoke( typeElement );
|
||||
}
|
||||
catch ( IllegalAccessException | IllegalArgumentException | InvocationTargetException e ) {
|
||||
return emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user