mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#592 Fix Decorator-support for component model 'spring' and 'jsr330', extend decorator integration-tests, add examples to @DecoratedWith javadoc
This commit is contained in:
parent
4eaacbcfe6
commit
590363cf2f
@ -29,14 +29,131 @@ import java.lang.annotation.Target;
|
||||
* <p>
|
||||
* A typical decorator implementation will be an abstract class and only implement/override a subset of the methods of
|
||||
* the mapper type which it decorates. All methods not implemented or overridden by the decorator will be implemented by
|
||||
* the code generator.
|
||||
* the code generator by delegating to the generated mapper implementation.
|
||||
* <p>
|
||||
* <b>NOTE:</b> The usage of decorated mappers differs depending on the selected component model.
|
||||
* <p>
|
||||
* <b>NOTE:</b> This annotation is not supported for the component model {@code cdi}. Use CDI's own
|
||||
* <a href="https://docs.jboss.org/cdi/spec/1.0/html/decorators.html">{@code @Decorator}</a> feature instead.
|
||||
* <p>
|
||||
* <b>NOTE:</b> The decorator feature when used with component model {@code jsr330} is considered <em>experimental</em>
|
||||
* and it may change in future releases.
|
||||
* <p>
|
||||
* <h2>Examples</h2>
|
||||
* <p>
|
||||
* For the examples below, consider the following mapper declaration:
|
||||
*
|
||||
* <pre>
|
||||
* @Mapper(componentModel = "...")
|
||||
* @DecoratedWith(PersonMapperDecorator.class)
|
||||
* public interface PersonMapper {
|
||||
*
|
||||
* @Mapping(target = "name", ignore = true)
|
||||
* PersonDto personToPersonDto(Person person);
|
||||
*
|
||||
* AddressDto addressToAddressDto(Address address); // not touched by the decorator
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <h3>1. Component model 'default'</h3>
|
||||
* <h4>Referencing the original mapper in the decorator</h4>
|
||||
* <p>
|
||||
* If a constructor with a single parameter accepting the type of the decorated mapper is present, a delegate with
|
||||
* generated implementations of all the mapper methods will be passed to this constructor. A typical implementation will
|
||||
* store the passed delegate in a field of the decorator and make use of it in the decorator methods.
|
||||
* store the passed delegate in a field of the decorator and make use of it in the decorator methods:
|
||||
*
|
||||
* <pre>
|
||||
* public abstract class PersonMapperDecorator implements PersonMapper {
|
||||
*
|
||||
* private PersonMapper delegate;
|
||||
*
|
||||
* public PersonMapperDecorator(PersonMapper delegate) {
|
||||
* this.delegate = delegate;
|
||||
* }
|
||||
*
|
||||
* @Override
|
||||
* public PersonDto personToPersonDto(Person person) {
|
||||
* PersonDto dto = delegate.personToPersonDto( person );
|
||||
* dto.setName( person.getFirstName() + " " + person.getLastName() );
|
||||
*
|
||||
* return dto;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <h4>Using the decorated mapper</h4>
|
||||
* <p>
|
||||
* Nothing special needs to be done. When using {@code Mappers.getMapper( PersonMapper.class )}, the <em>decorator</em>
|
||||
* is returned, with the injected original mapper.
|
||||
* <h3>2. Component model 'spring'</h3>
|
||||
* <h4>Referencing the original mapper in the decorator</h4>
|
||||
* <p>
|
||||
* The generated implementation of the original mapper is annotated with the Spring's {@code @Qualifier("delegate")}. To
|
||||
* autowire that bean in your decorator, add that qualifier annotation as well:
|
||||
*
|
||||
* <pre>
|
||||
* public abstract class PersonMapperDecorator implements PersonMapper {
|
||||
*
|
||||
* @Autowired
|
||||
* @Qualifier("delegate")
|
||||
* private PersonMapper delegate;
|
||||
*
|
||||
* @Override
|
||||
* public PersonDto personToPersonDto(Person person) {
|
||||
* PersonDto dto = delegate.personToPersonDto( person );
|
||||
* dto.setName( person.getFirstName() + " " + person.getLastName() );
|
||||
*
|
||||
* return dto;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <h4>Using the decorated mapper in the decorator</h4>
|
||||
* <p>
|
||||
* The generated class that extends the decorator is annotated with Spring's {@code @Primary} annotation. To autowire
|
||||
* the decorated mapper in the application, nothing special needs to be done:
|
||||
*
|
||||
* <pre>
|
||||
* @Autowired
|
||||
* private PersonMapper personMapper; // injects the decorator, with the injected original mapper
|
||||
* </pre>
|
||||
*
|
||||
* <h3>3. Component model 'jsr330'</h3>
|
||||
* <h4>Referencing the original mapper</h4>
|
||||
* <p>
|
||||
* JSR 330 doesn't specify qualifiers and only allows to specifically name the beans. Hence, the generated
|
||||
* implementation of the original mapper is annotated with the {@code @Named("fully-qualified-name-of-generated-impl")}.
|
||||
* To inject that bean in your decorator, add the same annotation to the delegate field:
|
||||
*
|
||||
* <pre>
|
||||
* public abstract class PersonMapperDecorator implements PersonMapper {
|
||||
*
|
||||
* @Inject
|
||||
* @Named("org.examples.PersonMapperImpl_")
|
||||
* private PersonMapper delegate;
|
||||
*
|
||||
* @Override
|
||||
* public PersonDto personToPersonDto(Person person) {
|
||||
* PersonDto dto = delegate.personToPersonDto( person );
|
||||
* dto.setName( person.getFirstName() + " " + person.getLastName() );
|
||||
*
|
||||
* return dto;
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <h4>Using the decorated mapper in the decorator</h4>
|
||||
* <p>
|
||||
* Unlike with the other component models, the usage site must be aware if a mapper is decorated or not, as for
|
||||
* decorated mappers, the parameterless {@code @Named} annotation must be added to select the <em>decorator</em> to be
|
||||
* injected:
|
||||
*
|
||||
* <pre>
|
||||
* @Inject
|
||||
* @Named
|
||||
* private PersonMapper personMapper; // injects the decorator, with the injected original mapper
|
||||
* </pre>
|
||||
* <p>
|
||||
* <b>NOTE:</b> The decorator feature is considered experimental and it may change in future releases. Currently
|
||||
* decorators are only supported for the default component model, not for the CDI and Spring models.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*/
|
||||
@ -45,10 +162,10 @@ import java.lang.annotation.Target;
|
||||
public @interface DecoratedWith {
|
||||
|
||||
/**
|
||||
* The decorator type. Must extend or implement the mapper type to which it is applied.
|
||||
* The decorator type. Must be an abstract class that extends or implements the mapper type to which it is applied.
|
||||
* <p>
|
||||
* The decorator type must either have a default constructor or a constructor with a single parameter accepting the
|
||||
* type of the decorated mapper.
|
||||
* For component-model {@code default}, the decorator type must either have a default constructor or a constructor
|
||||
* with a single parameter accepting the type of the decorated mapper.
|
||||
*
|
||||
* @return the decorator type
|
||||
*/
|
||||
|
@ -26,4 +26,6 @@ import org.mapstruct.itest.cdi.other.DateMapper;
|
||||
public interface DecoratedSourceTargetMapper {
|
||||
|
||||
Target sourceToTarget(Source source);
|
||||
|
||||
Target undecoratedSourceToTarget(Source source);
|
||||
}
|
||||
|
@ -23,15 +23,12 @@ import javax.decorator.Delegate;
|
||||
import javax.inject.Inject;
|
||||
|
||||
@Decorator
|
||||
public class SourceTargetMapperDecorator implements DecoratedSourceTargetMapper {
|
||||
public abstract class SourceTargetMapperDecorator implements DecoratedSourceTargetMapper {
|
||||
|
||||
@Delegate
|
||||
@Inject
|
||||
private DecoratedSourceTargetMapper delegate;
|
||||
|
||||
public SourceTargetMapperDecorator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Target sourceToTarget(Source source) {
|
||||
Target t = delegate.sourceToTarget( source );
|
||||
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.itest.jsr330;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.DecoratedWith;
|
||||
import org.mapstruct.itest.jsr330.other.DateMapper;
|
||||
|
||||
@Mapper(componentModel = "jsr330", uses = DateMapper.class)
|
||||
@DecoratedWith(SourceTargetMapperDecorator.class)
|
||||
public interface DecoratedSourceTargetMapper {
|
||||
|
||||
Target sourceToTarget(Source source);
|
||||
|
||||
Target undecoratedSourceToTarget(Source source);
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.itest.jsr330;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.DecoratedWith;
|
||||
import org.mapstruct.itest.jsr330.other.DateMapper;
|
||||
|
||||
@Mapper(componentModel = "jsr330", uses = DateMapper.class)
|
||||
@DecoratedWith(SecondSourceTargetMapperDecorator.class)
|
||||
public interface SecondDecoratedSourceTargetMapper {
|
||||
|
||||
Target sourceToTarget(Source source);
|
||||
|
||||
Target undecoratedSourceToTarget(Source source);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.itest.jsr330;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
public abstract class SecondSourceTargetMapperDecorator implements SecondDecoratedSourceTargetMapper {
|
||||
|
||||
@Inject
|
||||
@Named("org.mapstruct.itest.jsr330.SecondDecoratedSourceTargetMapperImpl_")
|
||||
private SecondDecoratedSourceTargetMapper delegate;
|
||||
|
||||
@Override
|
||||
public Target sourceToTarget(Source source) {
|
||||
Target t = delegate.sourceToTarget( source );
|
||||
t.setFoo( 43L );
|
||||
return t;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.itest.jsr330;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
public abstract class SourceTargetMapperDecorator implements DecoratedSourceTargetMapper {
|
||||
|
||||
@Inject
|
||||
@Named("org.mapstruct.itest.jsr330.DecoratedSourceTargetMapperImpl_")
|
||||
private DecoratedSourceTargetMapper delegate;
|
||||
|
||||
@Override
|
||||
public Target sourceToTarget(Source source) {
|
||||
Target t = delegate.sourceToTarget( source );
|
||||
t.setFoo( 43L );
|
||||
return t;
|
||||
}
|
||||
}
|
@ -18,9 +18,8 @@
|
||||
*/
|
||||
package org.mapstruct.itest.jsr330;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -30,13 +29,15 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for generation of JSR-330-based Mapper implementations
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
@ContextConfiguration(classes = SpringTestConfig.class )
|
||||
@RunWith( SpringJUnit4ClassRunner.class )
|
||||
@ContextConfiguration(classes = SpringTestConfig.class)
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class Jsr330BasedMapperTest {
|
||||
@Configuration
|
||||
@ComponentScan(basePackageClasses = Jsr330BasedMapperTest.class)
|
||||
@ -46,9 +47,16 @@ public class Jsr330BasedMapperTest {
|
||||
@Inject
|
||||
private SourceTargetMapper mapper;
|
||||
|
||||
@Inject
|
||||
@Named
|
||||
private DecoratedSourceTargetMapper decoratedMapper;
|
||||
|
||||
@Inject
|
||||
@Named
|
||||
private SecondDecoratedSourceTargetMapper secondDecoratedMapper;
|
||||
|
||||
@Test
|
||||
public void shouldCreateSpringBasedMapper() {
|
||||
public void shouldInjectJsr330BasedMapper() {
|
||||
Source source = new Source();
|
||||
|
||||
Target target = mapper.sourceToTarget( source );
|
||||
@ -57,4 +65,38 @@ public class Jsr330BasedMapperTest {
|
||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 42 ) );
|
||||
assertThat( target.getDate() ).isEqualTo( "1980" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInjectDecorator() {
|
||||
Source source = new Source();
|
||||
|
||||
Target target = decoratedMapper.sourceToTarget( source );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 43 ) );
|
||||
assertThat( target.getDate() ).isEqualTo( "1980" );
|
||||
|
||||
target = decoratedMapper.undecoratedSourceToTarget( source );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 42 ) );
|
||||
assertThat( target.getDate() ).isEqualTo( "1980" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInjectSecondDecorator() {
|
||||
Source source = new Source();
|
||||
|
||||
Target target = secondDecoratedMapper.sourceToTarget( source );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 43 ) );
|
||||
assertThat( target.getDate() ).isEqualTo( "1980" );
|
||||
|
||||
target = secondDecoratedMapper.undecoratedSourceToTarget( source );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 42 ) );
|
||||
assertThat( target.getDate() ).isEqualTo( "1980" );
|
||||
}
|
||||
}
|
||||
|
@ -27,4 +27,6 @@ import org.mapstruct.itest.spring.other.DateMapper;
|
||||
public interface DecoratedSourceTargetMapper {
|
||||
|
||||
Target sourceToTarget(Source source);
|
||||
|
||||
Target undecoratedSourceToTarget(Source source);
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.itest.spring;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.DecoratedWith;
|
||||
import org.mapstruct.itest.spring.other.DateMapper;
|
||||
|
||||
@Mapper( componentModel = "spring", uses = DateMapper.class )
|
||||
@DecoratedWith( SecondSourceTargetMapperDecorator.class )
|
||||
public interface SecondDecoratedSourceTargetMapper {
|
||||
|
||||
Target sourceToTarget(Source source);
|
||||
|
||||
Target undecoratedSourceToTarget(Source source);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.itest.spring;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
public abstract class SecondSourceTargetMapperDecorator implements SecondDecoratedSourceTargetMapper {
|
||||
|
||||
@Autowired
|
||||
@Qualifier( "delegate" )
|
||||
private DecoratedSourceTargetMapper delegate;
|
||||
|
||||
@Override
|
||||
public Target sourceToTarget(Source source) {
|
||||
Target t = delegate.sourceToTarget( source );
|
||||
t.setFoo( 43L );
|
||||
return t;
|
||||
}
|
||||
}
|
@ -20,20 +20,13 @@ package org.mapstruct.itest.spring;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@Primary
|
||||
public class SourceTargetMapperDecorator implements DecoratedSourceTargetMapper {
|
||||
public abstract class SourceTargetMapperDecorator implements DecoratedSourceTargetMapper {
|
||||
|
||||
@Autowired
|
||||
@Qualifier( "delegate" )
|
||||
private DecoratedSourceTargetMapper delegate;
|
||||
|
||||
public SourceTargetMapperDecorator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Target sourceToTarget(Source source) {
|
||||
Target t = delegate.sourceToTarget( source );
|
||||
|
@ -18,25 +18,24 @@
|
||||
*/
|
||||
package org.mapstruct.itest.spring;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mapstruct.itest.spring.SpringBasedMapperTest.SpringTestConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for generation of Spring-based Mapper implementations
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
@ContextConfiguration(classes = SpringTestConfig.class )
|
||||
@RunWith( SpringJUnit4ClassRunner.class )
|
||||
@ContextConfiguration(classes = SpringTestConfig.class)
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class SpringBasedMapperTest {
|
||||
|
||||
@Configuration
|
||||
@ -50,8 +49,11 @@ public class SpringBasedMapperTest {
|
||||
@Autowired
|
||||
private DecoratedSourceTargetMapper decoratedMapper;
|
||||
|
||||
@Autowired
|
||||
private SecondDecoratedSourceTargetMapper secondDecoratedMapper;
|
||||
|
||||
@Test
|
||||
public void shouldCreateSpringBasedMapper() {
|
||||
public void shouldInjectSpringBasedMapper() {
|
||||
Source source = new Source();
|
||||
|
||||
Target target = mapper.sourceToTarget( source );
|
||||
@ -69,5 +71,29 @@ public class SpringBasedMapperTest {
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 43 ) );
|
||||
assertThat( target.getDate() ).isEqualTo( "1980" );
|
||||
|
||||
target = decoratedMapper.undecoratedSourceToTarget( source );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 42 ) );
|
||||
assertThat( target.getDate() ).isEqualTo( "1980" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInjectSecondDecorator() {
|
||||
Source source = new Source();
|
||||
|
||||
Target target = secondDecoratedMapper.sourceToTarget( source );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 43 ) );
|
||||
assertThat( target.getDate() ).isEqualTo( "1980" );
|
||||
|
||||
target = secondDecoratedMapper.undecoratedSourceToTarget( source );
|
||||
|
||||
assertThat( target ).isNotNull();
|
||||
assertThat( target.getFoo() ).isEqualTo( Long.valueOf( 42 ) );
|
||||
assertThat( target.getDate() ).isEqualTo( "1980" );
|
||||
}
|
||||
}
|
||||
|
@ -179,6 +179,12 @@
|
||||
<version>${org.springframework.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Joda-Time -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
|
@ -85,6 +85,23 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- There is no compile dependency to Joda-Time; It's only required for testing the Joda conversions -->
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
|
@ -18,10 +18,11 @@
|
||||
*/
|
||||
package org.mapstruct.ap.internal.model;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.mapstruct.ap.internal.model.common.Type;
|
||||
import org.mapstruct.ap.internal.util.Collections;
|
||||
|
||||
/**
|
||||
* Mapper reference which is retrieved via Annotation-based dependency injection.
|
||||
@ -31,19 +32,26 @@ import org.mapstruct.ap.internal.util.Collections;
|
||||
*/
|
||||
public class AnnotationMapperReference extends MapperReference {
|
||||
|
||||
private final Annotation annotation;
|
||||
private final List<Annotation> annotations;
|
||||
|
||||
public AnnotationMapperReference(Type type, String variableName, Annotation annotation, boolean isUsed) {
|
||||
public AnnotationMapperReference(Type type, String variableName, List<Annotation> annotations, boolean isUsed) {
|
||||
super( type, variableName, isUsed );
|
||||
this.annotation = annotation;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
public Annotation getAnnotation() {
|
||||
return annotation;
|
||||
public List<Annotation> getAnnotations() {
|
||||
return annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Type> getImportTypes() {
|
||||
return Collections.asSet( annotation.getImportTypes(), super.getType() );
|
||||
Set<Type> types = new HashSet<Type>();
|
||||
types.add( getType() );
|
||||
|
||||
for ( Annotation annotation : annotations ) {
|
||||
types.addAll( annotation.getImportTypes() );
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
@ -50,14 +50,14 @@ public abstract class GeneratedType extends ModelElement {
|
||||
|
||||
private final List<Annotation> annotations;
|
||||
private final List<MappingMethod> methods;
|
||||
private final List<? extends Field> fields;
|
||||
private final SortedSet<Type> extraImportedTypes;
|
||||
|
||||
private final boolean suppressGeneratorTimestamp;
|
||||
private final boolean suppressGeneratorVersionComment;
|
||||
private final VersionInformation versionInformation;
|
||||
private final Accessibility accessibility;
|
||||
private final Constructor constructor;
|
||||
private List<? extends Field> fields;
|
||||
private Constructor constructor;
|
||||
|
||||
/**
|
||||
* Type representing the {@code @Generated} annotation
|
||||
@ -128,10 +128,14 @@ public abstract class GeneratedType extends ModelElement {
|
||||
return methods;
|
||||
}
|
||||
|
||||
public List<? extends ModelElement> getFields() {
|
||||
public List<? extends Field> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(List<? extends Field> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
public boolean isSuppressGeneratorTimestamp() {
|
||||
return suppressGeneratorTimestamp;
|
||||
}
|
||||
@ -182,6 +186,10 @@ public abstract class GeneratedType extends ModelElement {
|
||||
return constructor;
|
||||
}
|
||||
|
||||
public void removeConstructor() {
|
||||
constructor = null;
|
||||
}
|
||||
|
||||
protected void addWithDependents(Collection<Type> collection, Type typeToAdd) {
|
||||
if ( typeToAdd == null ) {
|
||||
return;
|
||||
|
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.mapstruct.ap.internal.processor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
|
||||
@ -25,6 +27,8 @@ import javax.lang.model.element.TypeElement;
|
||||
|
||||
import org.mapstruct.ap.internal.model.Annotation;
|
||||
import org.mapstruct.ap.internal.model.AnnotationMapperReference;
|
||||
import org.mapstruct.ap.internal.model.Decorator;
|
||||
import org.mapstruct.ap.internal.model.Field;
|
||||
import org.mapstruct.ap.internal.model.Mapper;
|
||||
import org.mapstruct.ap.internal.model.MapperReference;
|
||||
import org.mapstruct.ap.internal.model.common.TypeFactory;
|
||||
@ -64,27 +68,55 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
|
||||
if ( !requiresGenerationOfDecoratorClass() ) {
|
||||
mapper.removeDecorator();
|
||||
}
|
||||
else if ( mapper.getDecorator() != null ) {
|
||||
adjustDecorator( mapper );
|
||||
}
|
||||
|
||||
List<Annotation> annotations = getMapperReferenceAnnotations();
|
||||
ListIterator<MapperReference> iterator = mapper.getReferencedMappers().listIterator();
|
||||
while ( iterator.hasNext() ) {
|
||||
MapperReference reference = iterator.next();
|
||||
iterator.remove();
|
||||
iterator.add( replacementMapperReference( reference ) );
|
||||
iterator.add( replacementMapperReference( reference, annotations ) );
|
||||
}
|
||||
|
||||
return mapper;
|
||||
}
|
||||
|
||||
protected void adjustDecorator(Mapper mapper) {
|
||||
Decorator decorator = mapper.getDecorator();
|
||||
|
||||
for ( Annotation typeAnnotation : getDecoratorAnnotations() ) {
|
||||
decorator.addAnnotation( typeAnnotation );
|
||||
}
|
||||
|
||||
decorator.removeConstructor();
|
||||
|
||||
|
||||
List<Annotation> annotations = getDelegatorReferenceAnnotations( mapper );
|
||||
List<Field> replacement = new ArrayList<Field>();
|
||||
if ( !decorator.getMethods().isEmpty() ) {
|
||||
for ( Field field : decorator.getFields() ) {
|
||||
replacement.add( replacementMapperReference( field, annotations ) );
|
||||
}
|
||||
}
|
||||
decorator.setFields( replacement );
|
||||
}
|
||||
|
||||
protected List<Annotation> getDelegatorReferenceAnnotations(Mapper mapper) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param originalReference the reference to be replaced
|
||||
*
|
||||
* @return the mapper reference replacing the original one
|
||||
*/
|
||||
protected MapperReference replacementMapperReference(MapperReference originalReference) {
|
||||
protected MapperReference replacementMapperReference(Field originalReference, List<Annotation> annotations) {
|
||||
return new AnnotationMapperReference(
|
||||
originalReference.getType(),
|
||||
originalReference.getVariableName(),
|
||||
getMapperReferenceAnnotation(),
|
||||
annotations,
|
||||
originalReference.isUsed()
|
||||
);
|
||||
}
|
||||
@ -99,10 +131,17 @@ public abstract class AnnotationBasedComponentModelProcessor implements ModelEle
|
||||
*/
|
||||
protected abstract List<Annotation> getTypeAnnotations(Mapper mapper);
|
||||
|
||||
/**
|
||||
* @return the annotation(s) to be added at the decorator of the mapper
|
||||
*/
|
||||
protected List<Annotation> getDecoratorAnnotations() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the annotation of the field for the mapper reference
|
||||
*/
|
||||
protected abstract Annotation getMapperReferenceAnnotation();
|
||||
protected abstract List<Annotation> getMapperReferenceAnnotations();
|
||||
|
||||
/**
|
||||
* @return if a decorator (sub-)class needs to be generated or not
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.mapstruct.ap.internal.processor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -46,8 +47,8 @@ public class CdiComponentProcessor extends AnnotationBasedComponentModelProcesso
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Annotation getMapperReferenceAnnotation() {
|
||||
return new Annotation( getTypeFactory().getType( "javax.inject.Inject" ) );
|
||||
protected List<Annotation> getMapperReferenceAnnotations() {
|
||||
return Arrays.asList( new Annotation( getTypeFactory().getType( "javax.inject.Inject" ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,11 +18,13 @@
|
||||
*/
|
||||
package org.mapstruct.ap.internal.processor;
|
||||
|
||||
import org.mapstruct.ap.internal.model.Annotation;
|
||||
import org.mapstruct.ap.internal.model.Mapper;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.ap.internal.model.Annotation;
|
||||
import org.mapstruct.ap.internal.model.Mapper;
|
||||
|
||||
/**
|
||||
* A {@link ModelElementProcessor} which converts the given {@link Mapper}
|
||||
* object into a JSR 330 style bean in case "jsr330" is configured as the
|
||||
@ -39,16 +41,46 @@ public class Jsr330ComponentProcessor extends AnnotationBasedComponentModelProce
|
||||
|
||||
@Override
|
||||
protected List<Annotation> getTypeAnnotations(Mapper mapper) {
|
||||
return Collections.singletonList( new Annotation( getTypeFactory().getType( "javax.inject.Named" ) ) );
|
||||
if ( mapper.getDecorator() == null ) {
|
||||
return Collections.singletonList( named() );
|
||||
}
|
||||
else {
|
||||
return Collections.singletonList( namedDelegate( mapper ) );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Annotation getMapperReferenceAnnotation() {
|
||||
return new Annotation( getTypeFactory().getType( "javax.inject.Inject" ) );
|
||||
protected List<Annotation> getDecoratorAnnotations() {
|
||||
return Collections.singletonList( named() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Annotation> getDelegatorReferenceAnnotations(Mapper mapper) {
|
||||
return Arrays.asList( inject(), namedDelegate( mapper ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Annotation> getMapperReferenceAnnotations() {
|
||||
return Collections.singletonList( inject() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requiresGenerationOfDecoratorClass() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private Annotation named() {
|
||||
return new Annotation( getTypeFactory().getType( "javax.inject.Named" ) );
|
||||
}
|
||||
|
||||
private Annotation namedDelegate(Mapper mapper) {
|
||||
return new Annotation(
|
||||
getTypeFactory().getType( "javax.inject.Named" ),
|
||||
Collections.singletonList( '"' + mapper.getPackageName() + "." + mapper.getName() + '"' )
|
||||
);
|
||||
}
|
||||
|
||||
private Annotation inject() {
|
||||
return new Annotation( getTypeFactory().getType( "javax.inject.Inject" ) );
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ package org.mapstruct.ap.internal.processor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.ap.internal.model.Annotation;
|
||||
@ -42,26 +43,58 @@ public class SpringComponentProcessor extends AnnotationBasedComponentModelProce
|
||||
@Override
|
||||
protected List<Annotation> getTypeAnnotations(Mapper mapper) {
|
||||
List<Annotation> typeAnnotations = new ArrayList<Annotation>();
|
||||
typeAnnotations.add( new Annotation( getTypeFactory().getType( "org.springframework.stereotype.Component" ) ) );
|
||||
typeAnnotations.add( component() );
|
||||
|
||||
if ( mapper.getDecorator() != null ) {
|
||||
Annotation qualifier = new Annotation(
|
||||
getTypeFactory().getType( "org.springframework.beans.factory.annotation.Qualifier" ),
|
||||
Arrays.asList( "\"delegate\"" )
|
||||
);
|
||||
typeAnnotations.add( qualifier );
|
||||
typeAnnotations.add( qualifierDelegate() );
|
||||
}
|
||||
|
||||
return typeAnnotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Annotation getMapperReferenceAnnotation() {
|
||||
return new Annotation( getTypeFactory().getType( "org.springframework.beans.factory.annotation.Autowired" ) );
|
||||
protected List<Annotation> getDecoratorAnnotations() {
|
||||
return Arrays.asList(
|
||||
component(),
|
||||
primary()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Annotation> getMapperReferenceAnnotations() {
|
||||
return Collections.singletonList(
|
||||
autowired()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Annotation> getDelegatorReferenceAnnotations(Mapper mapper) {
|
||||
return Arrays.asList(
|
||||
autowired(),
|
||||
qualifierDelegate()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean requiresGenerationOfDecoratorClass() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private Annotation autowired() {
|
||||
return new Annotation( getTypeFactory().getType( "org.springframework.beans.factory.annotation.Autowired" ) );
|
||||
}
|
||||
|
||||
private Annotation qualifierDelegate() {
|
||||
return new Annotation(
|
||||
getTypeFactory().getType( "org.springframework.beans.factory.annotation.Qualifier" ),
|
||||
Collections.singletonList( "\"delegate\"" ) );
|
||||
}
|
||||
|
||||
private Annotation primary() {
|
||||
return new Annotation( getTypeFactory().getType( "org.springframework.context.annotation.Primary" ) );
|
||||
}
|
||||
|
||||
private Annotation component() {
|
||||
return new Annotation( getTypeFactory().getType( "org.springframework.stereotype.Component" ) );
|
||||
}
|
||||
}
|
||||
|
@ -18,5 +18,7 @@
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
<#list annotations as annotation>
|
||||
<#nt><@includeModel object=annotation/>
|
||||
</#list>
|
||||
private <@includeModel object=type/> ${variableName};
|
@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.decorator.jsr330;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mapstruct.ap.test.decorator.Address;
|
||||
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||
import org.mapstruct.ap.test.decorator.Person;
|
||||
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for the application of decorators using component model jsr330.
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
@WithClasses({
|
||||
Person.class,
|
||||
PersonDto.class,
|
||||
Address.class,
|
||||
AddressDto.class,
|
||||
PersonMapper.class,
|
||||
PersonMapperDecorator.class
|
||||
})
|
||||
@IssueKey("592")
|
||||
@RunWith(AnnotationProcessorTestRunner.class)
|
||||
@ComponentScan(basePackageClasses = Jsr330DecoratorTest.class)
|
||||
@Configuration
|
||||
public class Jsr330DecoratorTest {
|
||||
|
||||
@Inject
|
||||
@Named
|
||||
private PersonMapper personMapper;
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void springUp() {
|
||||
context = new AnnotationConfigApplicationContext( getClass() );
|
||||
context.getAutowireCapableBeanFactory().autowireBean( this );
|
||||
}
|
||||
|
||||
@After
|
||||
public void springDown() {
|
||||
if ( context != null ) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInvokeDecoratorMethods() {
|
||||
//given
|
||||
Calendar birthday = Calendar.getInstance();
|
||||
birthday.set( 1928, 4, 23 );
|
||||
Person person = new Person( "Gary", "Crant", birthday.getTime(), new Address( "42 Ocean View Drive" ) );
|
||||
|
||||
//when
|
||||
PersonDto personDto = personMapper.personToPersonDto( person );
|
||||
|
||||
//then
|
||||
assertThat( personDto ).isNotNull();
|
||||
assertThat( personDto.getName() ).isEqualTo( "Gary Crant" );
|
||||
assertThat( personDto.getAddress() ).isNotNull();
|
||||
assertThat( personDto.getAddress().getAddressLine() ).isEqualTo( "42 Ocean View Drive" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDelegateNonDecoratedMethodsToDefaultImplementation() {
|
||||
//given
|
||||
Address address = new Address( "42 Ocean View Drive" );
|
||||
|
||||
//when
|
||||
AddressDto addressDto = personMapper.addressToAddressDto( address );
|
||||
|
||||
//then
|
||||
assertThat( addressDto ).isNotNull();
|
||||
assertThat( addressDto.getAddressLine() ).isEqualTo( "42 Ocean View Drive" );
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.decorator.jsr330;
|
||||
|
||||
import org.mapstruct.DecoratedWith;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ap.test.decorator.Address;
|
||||
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||
import org.mapstruct.ap.test.decorator.Person;
|
||||
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||
|
||||
@Mapper(componentModel = "jsr330")
|
||||
@DecoratedWith(PersonMapperDecorator.class)
|
||||
public interface PersonMapper {
|
||||
|
||||
@Mapping( target = "name", ignore = true )
|
||||
PersonDto personToPersonDto(Person person);
|
||||
|
||||
AddressDto addressToAddressDto(Address address);
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.decorator.jsr330;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.mapstruct.ap.test.decorator.Person;
|
||||
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||
|
||||
public abstract class PersonMapperDecorator implements PersonMapper {
|
||||
|
||||
@Inject
|
||||
@Named("org.mapstruct.ap.test.decorator.jsr330.PersonMapperImpl_")
|
||||
private PersonMapper delegate;
|
||||
|
||||
@Override
|
||||
public PersonDto personToPersonDto(Person person) {
|
||||
PersonDto dto = delegate.personToPersonDto( person );
|
||||
dto.setName( person.getFirstName() + " " + person.getLastName() );
|
||||
|
||||
return dto;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.decorator.spring;
|
||||
|
||||
import org.mapstruct.DecoratedWith;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ap.test.decorator.Address;
|
||||
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||
import org.mapstruct.ap.test.decorator.Person;
|
||||
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
@DecoratedWith(PersonMapperDecorator.class)
|
||||
public interface PersonMapper {
|
||||
|
||||
@Mapping( target = "name", ignore = true )
|
||||
PersonDto personToPersonDto(Person person);
|
||||
|
||||
AddressDto addressToAddressDto(Address address);
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.decorator.spring;
|
||||
|
||||
import org.mapstruct.ap.test.decorator.Person;
|
||||
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
public abstract class PersonMapperDecorator implements PersonMapper {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("delegate")
|
||||
private PersonMapper delegate;
|
||||
|
||||
@Override
|
||||
public PersonDto personToPersonDto(Person person) {
|
||||
PersonDto dto = delegate.personToPersonDto( person );
|
||||
dto.setName( person.getFirstName() + " " + person.getLastName() );
|
||||
|
||||
return dto;
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* Copyright 2012-2015 Gunnar Morling (http://www.gunnarmorling.de/)
|
||||
* and/or other contributors as indicated by the @authors tag. See the
|
||||
* copyright.txt file in the distribution for a full listing of all
|
||||
* contributors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.mapstruct.ap.test.decorator.spring;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mapstruct.ap.test.decorator.Address;
|
||||
import org.mapstruct.ap.test.decorator.AddressDto;
|
||||
import org.mapstruct.ap.test.decorator.Person;
|
||||
import org.mapstruct.ap.test.decorator.PersonDto;
|
||||
import org.mapstruct.ap.testutil.IssueKey;
|
||||
import org.mapstruct.ap.testutil.WithClasses;
|
||||
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.fest.assertions.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test for the application of decorators using component model spring.
|
||||
*
|
||||
* @author Andreas Gudian
|
||||
*/
|
||||
@WithClasses({
|
||||
Person.class,
|
||||
PersonDto.class,
|
||||
Address.class,
|
||||
AddressDto.class,
|
||||
PersonMapper.class,
|
||||
PersonMapperDecorator.class
|
||||
})
|
||||
@IssueKey("592")
|
||||
@RunWith(AnnotationProcessorTestRunner.class)
|
||||
@ComponentScan(basePackageClasses = SpringDecoratorTest.class)
|
||||
@Configuration
|
||||
public class SpringDecoratorTest {
|
||||
|
||||
@Autowired
|
||||
private PersonMapper personMapper;
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void springUp() {
|
||||
context = new AnnotationConfigApplicationContext( getClass() );
|
||||
context.getAutowireCapableBeanFactory().autowireBean( this );
|
||||
}
|
||||
|
||||
@After
|
||||
public void springDown() {
|
||||
if ( context != null ) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldInvokeDecoratorMethods() {
|
||||
//given
|
||||
Calendar birthday = Calendar.getInstance();
|
||||
birthday.set( 1928, 4, 23 );
|
||||
Person person = new Person( "Gary", "Crant", birthday.getTime(), new Address( "42 Ocean View Drive" ) );
|
||||
|
||||
//when
|
||||
PersonDto personDto = personMapper.personToPersonDto( person );
|
||||
|
||||
//then
|
||||
assertThat( personDto ).isNotNull();
|
||||
assertThat( personDto.getName() ).isEqualTo( "Gary Crant" );
|
||||
assertThat( personDto.getAddress() ).isNotNull();
|
||||
assertThat( personDto.getAddress().getAddressLine() ).isEqualTo( "42 Ocean View Drive" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDelegateNonDecoratedMethodsToDefaultImplementation() {
|
||||
//given
|
||||
Address address = new Address( "42 Ocean View Drive" );
|
||||
|
||||
//when
|
||||
AddressDto addressDto = personMapper.addressToAddressDto( address );
|
||||
|
||||
//then
|
||||
assertThat( addressDto ).isNotNull();
|
||||
assertThat( addressDto.getAddressLine() ).isEqualTo( "42 Ocean View Drive" );
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user