diff --git a/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc b/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc index 24f019fa6..91f4afb1c 100644 --- a/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc +++ b/documentation/src/main/asciidoc/chapter-5-data-type-conversions.asciidoc @@ -122,6 +122,9 @@ public interface CarMapper { * Between `String` and `StringBuilder` +* Between `java.net.URL` and `String`. +** When converting from a `String`, the value needs to be a valid https://en.wikipedia.org/wiki/URL[URL] otherwise a `MalformedURLException` is thrown. + [[mapping-object-references]] === Mapping object references diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java index 20fb8a2fe..e88bb93b8 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/ConversionUtils.java @@ -7,6 +7,7 @@ package org.mapstruct.ap.internal.conversion; import java.math.BigDecimal; import java.math.BigInteger; +import java.net.URL; import java.sql.Time; import java.sql.Timestamp; import java.text.DecimalFormat; @@ -254,4 +255,15 @@ public final class ConversionUtils { public static String uuid(ConversionContext conversionContext) { return typeReferenceName( conversionContext, UUID.class ); } + + /** + * Name for {@link java.net.URL}. + * + * @param conversionContext Conversion context + * + * @return Name or fully-qualified name. + */ + public static String url(ConversionContext conversionContext) { + return typeReferenceName( conversionContext, URL.class ); + } } diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/Conversions.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/Conversions.java index 4b3ab2a81..e01248105 100755 --- a/processor/src/main/java/org/mapstruct/ap/internal/conversion/Conversions.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/Conversions.java @@ -7,6 +7,7 @@ package org.mapstruct.ap.internal.conversion; import java.math.BigDecimal; import java.math.BigInteger; +import java.net.URL; import java.sql.Time; import java.sql.Timestamp; import java.time.Duration; @@ -193,6 +194,8 @@ public class Conversions { register( Currency.class, String.class, new CurrencyToStringConversion() ); register( UUID.class, String.class, new UUIDToStringConversion() ); + + registerURLConversion(); } private void registerJodaConversions() { @@ -294,6 +297,16 @@ public class Conversions { } } + private void registerURLConversion() { + if ( isJavaURLAvailable() ) { + register( URL.class, String.class, new URLToStringConversion() ); + } + } + + private boolean isJavaURLAvailable() { + return typeFactory.isTypeAvailable( "java.net.URL" ); + } + private void register(Class sourceClass, Class targetClass, ConversionProvider conversion) { Type sourceType = typeFactory.getType( sourceClass ); Type targetType = typeFactory.getType( targetClass ); diff --git a/processor/src/main/java/org/mapstruct/ap/internal/conversion/URLToStringConversion.java b/processor/src/main/java/org/mapstruct/ap/internal/conversion/URLToStringConversion.java new file mode 100644 index 000000000..716dfb3bb --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/internal/conversion/URLToStringConversion.java @@ -0,0 +1,46 @@ +/* + * 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.conversion; + +import org.mapstruct.ap.internal.model.common.ConversionContext; +import org.mapstruct.ap.internal.model.common.Type; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Set; + +import static org.mapstruct.ap.internal.conversion.ConversionUtils.url; +import static org.mapstruct.ap.internal.util.Collections.asSet; + +/** + * Conversion between {@link java.net.URL} and {@link String}. + * + * @author Adam Szatyin + */ +public class URLToStringConversion extends SimpleConversion { + @Override + protected String getToExpression(ConversionContext conversionContext) { + return ".toString()"; + } + + @Override + protected String getFromExpression(ConversionContext conversionContext) { + return "new " + url( conversionContext ) + "( )"; + } + + @Override + protected Set getFromConversionImportTypes(final ConversionContext conversionContext) { + return asSet( conversionContext.getTypeFactory().getType( URL.class ) ); + } + + @Override + protected List getFromConversionExceptionTypes(ConversionContext conversionContext) { + return java.util.Collections.singletonList( + conversionContext.getTypeFactory().getType( MalformedURLException.class ) + ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/url/Source.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/url/Source.java new file mode 100644 index 000000000..ece0501a0 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/url/Source.java @@ -0,0 +1,33 @@ +/* + * 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.conversion.url; + +import java.net.URL; + +/** + * @author Adam Szatyin + */ +public class Source { + private URL url; + + private URL invalidURL; + + public URL getURL() { + return url; + } + + public void setURL(URL url) { + this.url = url; + } + + public URL getInvalidURL() { + return invalidURL; + } + + public void setInvalidURL(URL invalidURL) { + this.invalidURL = invalidURL; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/url/Target.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/url/Target.java new file mode 100644 index 000000000..060f5582e --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/url/Target.java @@ -0,0 +1,30 @@ +/* + * 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.conversion.url; + +/** + * @author Adam Szatyin + */ +public class Target { + private String url; + private String invalidURL; + + public String getURL() { + return this.url; + } + + public void setURL(final String url) { + this.url = url; + } + + public String getInvalidURL() { + return this.invalidURL; + } + + public void setInvalidURL(final String invalidURL) { + this.invalidURL = invalidURL; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/url/URLConversionTest.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/url/URLConversionTest.java new file mode 100644 index 000000000..bd1eed148 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/url/URLConversionTest.java @@ -0,0 +1,76 @@ +/* + * 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.conversion.url; + +import org.mapstruct.ap.testutil.ProcessorTest; +import org.mapstruct.ap.testutil.WithClasses; + +import java.net.MalformedURLException; +import java.net.URL; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * Tests conversions between {@link java.net.URL} and String. + * + * @author Adam Szatyin + */ +@WithClasses({ Source.class, Target.class, URLMapper.class }) +public class URLConversionTest { + + @ProcessorTest + public void shouldApplyURLConversion() throws MalformedURLException { + Source source = new Source(); + source.setURL( new URL("https://mapstruct.org/") ); + + Target target = URLMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getURL() ).isEqualTo( source.getURL().toString() ); + } + + @ProcessorTest + public void shouldApplyReverseURLConversion() throws MalformedURLException { + Target target = new Target(); + target.setURL( "https://mapstruct.org/" ); + + Source source = URLMapper.INSTANCE.targetToSource( target ); + + assertThat( source ).isNotNull(); + assertThat( source.getURL() ).isEqualTo( new URL( target.getURL() ) ); + } + + @ProcessorTest + public void shouldHandleInvalidURLString() { + Target target = new Target(); + target.setInvalidURL( "XXXXXXXXX" ); + + assertThatThrownBy( () -> URLMapper.INSTANCE.targetToSource( target ) ) + .isInstanceOf( RuntimeException.class ) + .getRootCause().isInstanceOf( MalformedURLException.class ); + } + + @ProcessorTest + public void shouldHandleInvalidURLStringWithMalformedURLException() { + Target target = new Target(); + target.setInvalidURL( "XXXXXXXXX" ); + + assertThatThrownBy( () -> URLMapper.INSTANCE.targetToSourceWithMalformedURLException( target ) ) + .isInstanceOf( MalformedURLException.class ); + } + + @ProcessorTest + public void shouldHandleNullURLString() { + Source source = new Source(); + + Target target = URLMapper.INSTANCE.sourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getURL() ).isNull(); + assertThat( target.getInvalidURL() ).isNull(); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/conversion/url/URLMapper.java b/processor/src/test/java/org/mapstruct/ap/test/conversion/url/URLMapper.java new file mode 100644 index 000000000..18fc5bc7d --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/conversion/url/URLMapper.java @@ -0,0 +1,23 @@ +/* + * 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.conversion.url; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.net.MalformedURLException; + +@Mapper +public interface URLMapper { + + URLMapper INSTANCE = Mappers.getMapper( URLMapper.class ); + + Target sourceToTarget(Source source); + + Source targetToSource(Target target); + + Source targetToSourceWithMalformedURLException(Target target) throws MalformedURLException; +}