#2837 Add support for text blocks in expressions

This commit is contained in:
Filip Hrisafov 2022-06-05 18:16:00 +02:00
parent 22ad9f636d
commit fa800926e7
12 changed files with 283 additions and 1 deletions

View File

@ -122,6 +122,13 @@ public class MavenIntegrationTest {
void recordsCrossModuleTest() {
}
@ProcessorTest(baseDir = "expressionTextBlocksTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC
})
@EnabledForJreRange(min = JRE.JAVA_17)
void expressionTextBlocksTest() {
}
@ProcessorTest(baseDir = "kotlinDataTest", processorTypes = {
ProcessorTest.ProcessorType.JAVAC
}, forkJvm = true)

View File

@ -0,0 +1,22 @@
<?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>expressionTextBlocksTest</artifactId>
<packaging>jar</packaging>
</project>

View File

@ -0,0 +1,22 @@
/*
* 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.textBlocks;
/**
* @author Filip Hrisafov
*/
public class Car {
private WheelPosition wheelPosition;
public WheelPosition getWheelPosition() {
return wheelPosition;
}
public void setWheelPosition(WheelPosition wheelPosition) {
this.wheelPosition = wheelPosition;
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.textBlocks;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;
import org.mapstruct.factory.Mappers;
/**
* @author Filip Hrisafov
*/
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface CarAndWheelMapper {
CarAndWheelMapper INSTANCE = Mappers.getMapper( CarAndWheelMapper.class );
@Mapping(target = "wheelPosition",
expression =
"""
java(
source.getWheelPosition() == null ?
null :
source.getWheelPosition().getPosition()
)
""")
CarDto carDtoFromCar(Car source);
@Mapping(target = "wheelPosition",
expression = """
java(
source.wheelPosition() == null ?
null :
new WheelPosition(source.wheelPosition())
)
""")
Car carFromCarDto(CarDto source);
}

View File

@ -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.itest.textBlocks;
import java.util.List;
/**
* @author Filip Hrisafov
*/
public record CarDto(String wheelPosition) {
}

View File

@ -0,0 +1,22 @@
/*
* 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.textBlocks;
/**
* @author Filip Hrisafov
*/
public class WheelPosition {
private final String position;
public WheelPosition(String position) {
this.position = position;
}
public String getPosition() {
return position;
}
}

View File

@ -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.textBlocks;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
public class TextBlocksTest {
@Test
public void textBlockExpressionShouldWork() {
Car car = new Car();
car.setWheelPosition( new WheelPosition( "left" ) );
CarDto carDto = CarAndWheelMapper.INSTANCE.carDtoFromCar(car);
assertThat( carDto ).isNotNull();
assertThat( carDto.wheelPosition() )
.isEqualTo( "left" );
}
}

View File

@ -37,7 +37,7 @@ import org.mapstruct.tools.gem.GemValue;
*/
public class MappingOptions extends DelegatingOptions {
private static final Pattern JAVA_EXPRESSION = Pattern.compile( "^java\\((.*)\\)$" );
private static final Pattern JAVA_EXPRESSION = Pattern.compile( "^\\s*java\\((.*)\\)\\s*$", Pattern.DOTALL );
private final String sourceName;
private final String constant;

View File

@ -5,6 +5,9 @@
*/
package org.mapstruct.ap.test.source.defaultExpressions.java;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.Date;
import org.mapstruct.ap.testutil.ProcessorTest;
@ -46,6 +49,23 @@ public class JavaDefaultExpressionTest {
assertThat( target.getSourceDate() ).isEqualTo( new Date( 30L ) );
}
@ProcessorTest
@WithClasses({ Source.class, Target.class, MultiLineDefaultExpressionMapper.class })
public void testMultiLineJavaDefaultExpression() {
Source source = new Source();
Target target = MultiLineDefaultExpressionMapper.INSTANCE.sourceToTarget( source );
assertThat( target ).isNotNull();
assertThat( target.getSourceId() ).isEqualTo( "test" );
assertThat( target.getSourceDate() )
.isEqualTo( Date.from(
LocalDate.of( 2022, Month.JUNE, 5 )
.atTime( 17, 10 )
.toInstant( ZoneOffset.UTC )
) );
}
@ProcessorTest
@ExpectedCompilationOutcome(
value = CompilationResult.FAILED,

View File

@ -0,0 +1,44 @@
/*
* 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.source.defaultExpressions.java;
import java.time.LocalDate;
import java.time.Month;
import java.time.ZoneOffset;
import java.util.Date;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* @author Filip Hrisafov
*/
@Mapper(imports = { Date.class, LocalDate.class, ZoneOffset.class, Month.class })
public interface MultiLineDefaultExpressionMapper {
MultiLineDefaultExpressionMapper INSTANCE = Mappers.getMapper( MultiLineDefaultExpressionMapper.class );
@Mappings({
@Mapping(
target = "sourceId",
source = "id",
defaultExpression = "java( new StringBuilder()\n.append( \"test\" )\n.toString() )"
),
@Mapping(
target = "sourceDate",
source = "date",
defaultExpression = "java(" +
"Date.from(\n" +
"LocalDate.of( 2022, Month.JUNE, 5 )\n" +
".atTime( 17, 10 )\n" +
".toInstant( ZoneOffset.UTC )\n)" +
")"
)
})
Target sourceToTarget(Source s);
}

View File

@ -132,6 +132,31 @@ public class JavaExpressionTest {
assertThat( target.getList() ).isEqualTo( Arrays.asList( "test2" ) );
}
@ProcessorTest
@WithClasses({ Source.class, Target.class, TimeAndFormat.class, MultiLineExpressionMapper.class })
public void testMultiLineJavaExpressionInsertion() throws ParseException {
Source source = new Source();
String format = "dd-MM-yyyy,hh:mm:ss";
Date time = getTime( format, "09-01-2014,01:35:03" );
source.setFormat( format );
source.setTime( time );
Target target = MultiLineExpressionMapper.INSTANCE.mapUsingMultiLineExpression( source );
assertThat( target ).isNotNull();
assertThat( target.getTimeAndFormat().getTime() ).isEqualTo( time );
assertThat( target.getTimeAndFormat().getFormat() ).isEqualTo( format );
assertThat( target.getAnotherProp() ).isNull();
target = MultiLineExpressionMapper.INSTANCE.mapUsingMultiLineExpressionWithLeadingSpaces( source );
assertThat( target ).isNotNull();
assertThat( target.getTimeAndFormat().getTime() ).isEqualTo( time );
assertThat( target.getTimeAndFormat().getFormat() ).isEqualTo( format );
assertThat( target.getAnotherProp() ).isNull();
}
@IssueKey( "1851" )
@ProcessorTest
@WithClasses({

View File

@ -0,0 +1,37 @@
/*
* 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.source.expressions.java;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.ap.test.source.expressions.java.mapper.TimeAndFormat;
import org.mapstruct.factory.Mappers;
/**
* @author Filip Hrisafov
*/
@Mapper(imports = TimeAndFormat.class)
public interface MultiLineExpressionMapper {
MultiLineExpressionMapper INSTANCE = Mappers.getMapper( MultiLineExpressionMapper.class );
@Mappings({
@Mapping(target = "timeAndFormat", expression = "java( new TimeAndFormat(\ns.getTime(),\ns.getFormat()\n ))"),
@Mapping(target = "anotherProp", ignore = true)
})
Target mapUsingMultiLineExpression(Source s);
@Mappings({
@Mapping(
target = "timeAndFormat",
expression = " java( new TimeAndFormat(\ns.getTime(),\ns.getFormat()\n )) "
),
@Mapping(target = "anotherProp", ignore = true)
})
Target mapUsingMultiLineExpressionWithLeadingSpaces(Source s);
}