├── .gitignore
├── src
├── test
│ ├── java
│ │ └── io
│ │ │ └── beanmapper
│ │ │ └── spring
│ │ │ ├── unproxy
│ │ │ ├── Shop.java
│ │ │ ├── HibernateProxyContainer.java
│ │ │ └── HibernateAwareBeanUnproxyTest.java
│ │ │ ├── model
│ │ │ ├── Spoon.java
│ │ │ ├── Tag.java
│ │ │ ├── ArtistDto.java
│ │ │ ├── PersonView.java
│ │ │ ├── AssetDto.java
│ │ │ ├── OrganizationDto.java
│ │ │ ├── PersonDto.java
│ │ │ ├── PersonRepository.java
│ │ │ ├── PersonForm.java
│ │ │ ├── SpoonDrawerForm.java
│ │ │ ├── Artist.java
│ │ │ ├── ProductDto.java
│ │ │ ├── BaseEntity.java
│ │ │ ├── Asset.java
│ │ │ ├── Organization.java
│ │ │ ├── Product.java
│ │ │ └── Person.java
│ │ │ ├── web
│ │ │ ├── mockmvc
│ │ │ │ ├── fakedomain
│ │ │ │ │ ├── FakeForm.java
│ │ │ │ │ ├── FakeResult.java
│ │ │ │ │ ├── ContainingFakeService.java
│ │ │ │ │ ├── ContainingFakeResult.java
│ │ │ │ │ ├── FakeRepository.java
│ │ │ │ │ ├── ContainingFakeForm.java
│ │ │ │ │ ├── ContainingFake.java
│ │ │ │ │ ├── FakeBuildCommand.java
│ │ │ │ │ ├── FakeService.java
│ │ │ │ │ ├── Populator.java
│ │ │ │ │ ├── FakeBuilder.java
│ │ │ │ │ ├── FakeApplicationConfig.java
│ │ │ │ │ ├── Fake.java
│ │ │ │ │ ├── ContainingFakeController.java
│ │ │ │ │ ├── FakeWebMvcConfig.java
│ │ │ │ │ └── FakeControllerTest.java
│ │ │ │ ├── FakeController.java
│ │ │ │ ├── AbstractControllerTest.java
│ │ │ │ └── ContainingFakeControllerTest.java
│ │ │ ├── EntityFinderTest.java
│ │ │ ├── PersonController.java
│ │ │ ├── SpringDataEntityFinderTest.java
│ │ │ └── PersonControllerTest.java
│ │ │ ├── flusher
│ │ │ ├── CollTarget.java
│ │ │ ├── CollSource.java
│ │ │ └── JpaAfterClearFlusherTest.java
│ │ │ ├── exceptions
│ │ │ ├── ClassExpectationNotRegisteredExceptionTest.java
│ │ │ └── PrincipalIsNoInstanceOfUserDetailsExceptionTest.java
│ │ │ ├── converter
│ │ │ ├── BeanMapperConverterAdapterTest.java
│ │ │ ├── ConversionServiceBeanConverterTest.java
│ │ │ └── IdToEntityBeanConverterTest.java
│ │ │ ├── AbstractSpringTest.java
│ │ │ ├── PageableMapperTest.java
│ │ │ └── ApplicationConfig.java
│ └── resources
│ │ └── log4j.properties
└── main
│ └── java
│ └── io
│ └── beanmapper
│ └── spring
│ ├── security
│ ├── SpringRoleSecuredCheck.java
│ └── AbstractSpringSecuredCheck.java
│ ├── exceptions
│ ├── ClassExpectationNotRegisteredException.java
│ └── PrincipalIsNoInstanceOfUserDetailsException.java
│ ├── web
│ ├── converter
│ │ ├── StructuredBody.java
│ │ └── StructuredJsonMessageConverter.java
│ ├── mockmvc
│ │ ├── MockEntityConverter.java
│ │ ├── MockIdToEntityBeanConverter.java
│ │ ├── MockEntityFinder.java
│ │ └── MockMvcBeanMapper.java
│ ├── EntityFinder.java
│ ├── MergedForm.java
│ ├── WebRequestParameters.java
│ ├── MergePair.java
│ ├── SpringDataEntityFinder.java
│ └── MergedFormMethodArgumentResolver.java
│ ├── Lazy.java
│ ├── unproxy
│ └── HibernateAwareBeanUnproxy.java
│ ├── flusher
│ └── JpaAfterClearFlusher.java
│ ├── converter
│ ├── BeanMapperConverterAdapter.java
│ ├── ConversionServiceBeanConverter.java
│ └── IdToEntityBeanConverter.java
│ ├── util
│ └── JsonUtil.java
│ └── PageableMapper.java
├── owasp-suppressions.xml
├── .github
└── workflows
│ ├── maven.yml
│ └── release.yml
├── README.md
├── CHANGELOG.md
└── pom.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .settings
3 | .project
4 | /target/
5 | *.iml
6 | .idea
7 | .java-version
8 | .claude
9 | pom.xml.versionsBackup
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/unproxy/Shop.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.unproxy;
2 |
3 | public class Shop {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/Spoon.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public record Spoon(boolean polished) {
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/Tag.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public enum Tag {
4 | CUSTOMER,
5 | DEBTOR,
6 | UPSELLING
7 | }
8 |
--------------------------------------------------------------------------------
/owasp-suppressions.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/FakeForm.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | public class FakeForm {
4 |
5 | public String name;
6 | }
7 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/ArtistDto.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public class ArtistDto {
4 |
5 | public Long id;
6 |
7 | public String name;
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/PersonView.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public class PersonView {
4 |
5 | public String name;
6 |
7 | public String place;
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/FakeResult.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | public class FakeResult {
4 |
5 | public Long id;
6 | public String name;
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/AssetDto.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public class AssetDto {
4 |
5 | public Long id;
6 |
7 | public String name;
8 |
9 | public String isrc;
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/OrganizationDto.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public class OrganizationDto {
4 |
5 | public Long id;
6 |
7 | public String name;
8 |
9 | public String contact;
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/flusher/CollTarget.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.flusher;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class CollTarget {
7 |
8 | public List items = new ArrayList<>();
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/security/SpringRoleSecuredCheck.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.security;
2 |
3 | import io.beanmapper.config.RoleSecuredCheck;
4 |
5 | public class SpringRoleSecuredCheck extends AbstractSpringSecuredCheck implements RoleSecuredCheck {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/PersonDto.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public class PersonDto {
4 |
5 | public Long id;
6 |
7 | public String name;
8 |
9 | public String street;
10 |
11 | public String houseNumber;
12 |
13 | public String city;
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/ContainingFakeService.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | public class ContainingFakeService {
4 |
5 | public ContainingFake create(ContainingFake containingFake) {
6 | return containingFake;
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/test/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender
2 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
3 | log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
4 |
5 | log4j.rootCategory=INFO, stdout
6 | log4j.logger.com.mangofactory.swagger=WARN, stdout
7 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/ContainingFakeResult.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import io.beanmapper.annotations.BeanProperty;
4 |
5 | public class ContainingFakeResult {
6 |
7 | @BeanProperty("fake.name")
8 | public String fakeName;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/exceptions/ClassExpectationNotRegisteredException.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.exceptions;
2 |
3 | public class ClassExpectationNotRegisteredException extends RuntimeException {
4 |
5 | public ClassExpectationNotRegisteredException(String message) {
6 | super(message);
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/FakeRepository.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import java.util.Optional;
4 |
5 | import org.springframework.data.jpa.repository.JpaRepository;
6 |
7 | public interface FakeRepository extends JpaRepository {
8 |
9 | Optional findByName(String name);
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/PersonRepository.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.model;
5 |
6 | import org.springframework.data.jpa.repository.JpaRepository;
7 |
8 | public interface PersonRepository extends JpaRepository {
9 |
10 | Person findByName(String string);
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/PersonForm.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | import java.util.List;
4 |
5 | import io.beanmapper.annotations.BeanCollection;
6 |
7 | public class PersonForm {
8 |
9 | public String name;
10 |
11 | public String city;
12 |
13 | @BeanCollection(elementType = Tag.class)
14 | public List tags;
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/ContainingFakeForm.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import io.beanmapper.annotations.BeanIgnore;
4 | import io.beanmapper.annotations.BeanProperty;
5 |
6 | public class ContainingFakeForm {
7 |
8 | @BeanProperty("fake")
9 | public Long fakeId;
10 |
11 | @BeanIgnore
12 | public String passMe;
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/converter/StructuredBody.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.web.converter;
5 |
6 | import java.util.Set;
7 |
8 | /**
9 | * Wrapper for a read request body.
10 | *
11 | * @author Jeroen van Schagen
12 | * @since Nov 25, 2015
13 | */
14 | public record StructuredBody(Object body, Set propertyNames) {
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/exceptions/PrincipalIsNoInstanceOfUserDetailsException.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.exceptions;
2 |
3 | public class PrincipalIsNoInstanceOfUserDetailsException extends RuntimeException {
4 |
5 | private static final String MESSAGE = "The Security Principal is not an instance of UserDetails";
6 |
7 | public PrincipalIsNoInstanceOfUserDetailsException() {
8 | super(MESSAGE);
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/SpoonDrawerForm.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | import java.util.List;
4 |
5 | import io.beanmapper.annotations.BeanCollection;
6 |
7 | public class SpoonDrawerForm {
8 |
9 | @BeanCollection(elementType = Spoon.class)
10 | public List spoons;
11 |
12 | public static class SpoonForm {
13 | public Long id;
14 | public Boolean polished;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/flusher/CollSource.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.flusher;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import io.beanmapper.annotations.BeanCollection;
7 | import io.beanmapper.utils.Trinary;
8 |
9 | public class CollSource {
10 |
11 | @BeanCollection(elementType = CollTarget.class, flushAfterClear = Trinary.ENABLED)
12 | public List items = new ArrayList<>();
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/Lazy.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring;
5 |
6 | /**
7 | * Wrapper on object to retrieve only when desired.
8 | *
9 | * @author Jeroen van Schagen
10 | * @since Nov 13, 2015
11 | */
12 | public interface Lazy {
13 |
14 | /**
15 | * Retrieve the entity instance.
16 | * @return the entity instance
17 | */
18 | T get() throws Exception;
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/ContainingFake.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import jakarta.validation.constraints.NotNull;
4 |
5 | public class ContainingFake {
6 |
7 | private Fake fake;
8 |
9 | @NotNull
10 | private String mustNotBeNull;
11 |
12 | public Fake getFake() {
13 | return fake;
14 | }
15 |
16 | public void setFake(Fake fake) {
17 | this.fake = fake;
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/Artist.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public class Artist {
4 |
5 | private Long id;
6 |
7 | private String name;
8 |
9 | public Long getId() {
10 | return id;
11 | }
12 |
13 | public void setId(Long id) {
14 | this.id = id;
15 | }
16 |
17 | public String getName() {
18 | return name;
19 | }
20 |
21 | public void setName(String name) {
22 | this.name = name;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.github/workflows/maven.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: Java CI with Maven
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | call-workflow:
14 | uses: 42BV/42-github-workflows/.github/workflows/maven-test.yml@main
15 | with:
16 | java-version: 21
17 | secrets: inherit
18 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/exceptions/ClassExpectationNotRegisteredExceptionTest.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.exceptions;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertThrows;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | class ClassExpectationNotRegisteredExceptionTest {
8 |
9 | @Test
10 | void classExpectationNotRegisteredExceptionTest() {
11 | assertThrows(ClassExpectationNotRegisteredException.class, () -> {throw new ClassExpectationNotRegisteredException("Test");});
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/FakeBuildCommand.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import nl._42.heph.AbstractBuildCommand;
4 |
5 | public interface FakeBuildCommand extends AbstractBuildCommand {
6 |
7 | @Override
8 | default Fake findEntity(Fake entity) {
9 | return getRepository().findByName(entity.getName()).orElse(null);
10 | }
11 |
12 | FakeBuildCommand withName(String name);
13 |
14 | FakeBuildCommand withId(Long id);
15 |
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/FakeService.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import org.springframework.stereotype.Service;
4 |
5 | @Service
6 | public class FakeService {
7 |
8 | public Fake read(Fake fake) {
9 | return fake;
10 | }
11 |
12 | public Fake create(Fake fake) {
13 | return fake;
14 | }
15 |
16 | public Fake update(Fake fake) {
17 | return fake;
18 | }
19 |
20 | public Fake delete(Fake fake) {
21 | return fake;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/exceptions/PrincipalIsNoInstanceOfUserDetailsExceptionTest.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.exceptions;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertThrows;
4 |
5 | import org.junit.jupiter.api.Test;
6 |
7 | public class PrincipalIsNoInstanceOfUserDetailsExceptionTest {
8 |
9 | @Test
10 | void testPrincipalIsNoInstanceOfUserDetailsExceptionTest() {
11 | assertThrows(PrincipalIsNoInstanceOfUserDetailsException.class, () -> { throw new PrincipalIsNoInstanceOfUserDetailsException(); });
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/ProductDto.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | import java.util.List;
4 |
5 | import io.beanmapper.annotations.BeanCollection;
6 |
7 | public class ProductDto {
8 |
9 | public Long id;
10 |
11 | public String name;
12 |
13 | public String upc;
14 |
15 | @BeanCollection(elementType = AssetDto.class)
16 | public List assets;
17 |
18 | @BeanCollection(elementType = ArtistDto.class)
19 | public List artists;
20 |
21 | public OrganizationDto organization;
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/Populator.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import jakarta.annotation.PostConstruct;
4 |
5 | import org.springframework.stereotype.Component;
6 |
7 | @Component
8 | public class Populator {
9 |
10 | private final FakeBuilder fakeBuilder;
11 |
12 | public Populator(FakeBuilder fakeBuilder) {
13 | this.fakeBuilder = fakeBuilder;
14 | }
15 |
16 | @PostConstruct
17 | public void initData() {
18 | fakeBuilder.henk();
19 | fakeBuilder.piet();
20 | }
21 |
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/unproxy/HibernateProxyContainer.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.unproxy;
2 |
3 | import org.hibernate.proxy.HibernateProxy;
4 | import org.hibernate.proxy.LazyInitializer;
5 |
6 | public class HibernateProxyContainer {
7 |
8 | public class GeneratedProxy extends Shop implements HibernateProxy {
9 |
10 | @Override
11 | public Object writeReplace() {
12 | return null;
13 | }
14 |
15 | @Override
16 | public LazyInitializer getHibernateLazyInitializer() {
17 | return null;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/BaseEntity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.model;
5 |
6 | import jakarta.persistence.GeneratedValue;
7 | import jakarta.persistence.GenerationType;
8 | import jakarta.persistence.Id;
9 | import jakarta.persistence.MappedSuperclass;
10 |
11 | @MappedSuperclass
12 | public class BaseEntity {
13 |
14 | @Id
15 | @GeneratedValue(strategy = GenerationType.IDENTITY)
16 | private Long id;
17 |
18 | public Long getId() {
19 | return id;
20 | }
21 |
22 | public void setId(Long id) {
23 | this.id = id;
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/unproxy/HibernateAwareBeanUnproxy.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.unproxy;
2 |
3 | import java.util.Arrays;
4 |
5 | import io.beanmapper.core.unproxy.BeanUnproxy;
6 |
7 | import org.hibernate.proxy.HibernateProxy;
8 |
9 | public class HibernateAwareBeanUnproxy implements BeanUnproxy {
10 |
11 | /**
12 | * {@inheritDoc}
13 | */
14 | public Class> unproxy(Class> beanClass) {
15 | if (beanClass.getName().contains("$")
16 | && Arrays.asList(beanClass.getInterfaces()).contains(HibernateProxy.class)) {
17 | return beanClass.getSuperclass();
18 | }
19 | return beanClass;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/FakeBuilder.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import nl._42.heph.AbstractBuilder;
4 |
5 | import org.springframework.stereotype.Component;
6 |
7 | @Component
8 | public class FakeBuilder extends AbstractBuilder {
9 |
10 | @Override
11 | public FakeBuildCommand base() {
12 | return blank();
13 | }
14 |
15 | public Fake henk() {
16 | return base()
17 | .withName("Henk")
18 | .create();
19 | }
20 |
21 | public Fake piet() {
22 | return base()
23 | .withName("Piet")
24 | .create();
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/flusher/JpaAfterClearFlusher.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.flusher;
2 |
3 | import jakarta.persistence.EntityManager;
4 |
5 | import io.beanmapper.config.AfterClearFlusher;
6 |
7 | /**
8 | * Specific AfterClearFlusher for flushing JPA's EntityManager. This is called by
9 | * BeanMapper after calling clear on a collection.
10 | */
11 | public class JpaAfterClearFlusher implements AfterClearFlusher {
12 |
13 | private final EntityManager entityManager;
14 |
15 | public JpaAfterClearFlusher(EntityManager entityManager) {
16 | this.entityManager = entityManager;
17 | }
18 |
19 | @Override
20 | public void flush() {
21 | entityManager.flush();
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/mockmvc/MockEntityConverter.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc;
2 |
3 | import org.springframework.core.convert.converter.Converter;
4 | import org.springframework.data.domain.Persistable;
5 | import org.springframework.data.repository.CrudRepository;
6 |
7 | public class MockEntityConverter> implements Converter {
8 |
9 | private final CrudRepository repository;
10 |
11 | public MockEntityConverter(CrudRepository respository) {
12 | this.repository = respository;
13 | }
14 |
15 | @Override
16 | public T convert(String id) {
17 | return repository.findById(Long.valueOf(id)).orElse(null);
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Publish package to the Maven Central Repository
2 |
3 | on:
4 | workflow_dispatch:
5 | inputs:
6 | release-version:
7 | required: false
8 | description: Release-version (not required)
9 | next-version:
10 | required: false
11 | description: Next development-version. (not required)
12 | java-version:
13 | required: true
14 | default: '21'
15 | description: Java-version to use for the deployment.
16 |
17 | jobs:
18 | call-workflow:
19 | uses: 42BV/42-github-workflows/.github/workflows/maven-release.yml@main
20 | secrets: inherit
21 | with:
22 | release-version: ${{ github.event.inputs.release-version }}
23 | next-version: ${{ github.event.inputs.next-version }}
24 | java-version: ${{ github.event.inputs.java-version }}
25 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/Asset.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public class Asset {
4 |
5 | private Long id;
6 |
7 | private String name;
8 |
9 | private String isrc;
10 |
11 | private String internalMemo;
12 |
13 | public Long getId() {
14 | return id;
15 | }
16 |
17 | public void setId(Long id) {
18 | this.id = id;
19 | }
20 |
21 | public String getInternalMemo() {
22 | return internalMemo;
23 | }
24 |
25 | public void setInternalMemo(String internalMemo) {
26 | this.internalMemo = internalMemo;
27 | }
28 |
29 | public String getName() {
30 | return name;
31 | }
32 |
33 | public void setName(String name) {
34 | this.name = name;
35 | }
36 |
37 | public String getIsrc() {
38 | return isrc;
39 | }
40 |
41 | public void setIsrc(String isrc) {
42 | this.isrc = isrc;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/Organization.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | public class Organization {
4 |
5 | private Long id;
6 |
7 | private String name;
8 |
9 | private String contact;
10 |
11 | private String ourSecret;
12 |
13 | public Long getId() {
14 | return id;
15 | }
16 |
17 | public void setId(Long id) {
18 | this.id = id;
19 | }
20 |
21 | public String getName() {
22 | return name;
23 | }
24 |
25 | public void setName(String name) {
26 | this.name = name;
27 | }
28 |
29 | public String getContact() {
30 | return contact;
31 | }
32 |
33 | public void setContact(String contact) {
34 | this.contact = contact;
35 | }
36 |
37 | public String getOurSecret() {
38 | return ourSecret;
39 | }
40 |
41 | public void setOurSecret(String ourSecret) {
42 | this.ourSecret = ourSecret;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/FakeApplicationConfig.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import io.beanmapper.BeanMapper;
4 | import io.beanmapper.config.BeanMapperBuilder;
5 | import io.beanmapper.spring.converter.IdToEntityBeanConverter;
6 |
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.context.ApplicationContext;
9 | import org.springframework.context.annotation.Bean;
10 |
11 | public class FakeApplicationConfig {
12 |
13 | @Autowired
14 | private ApplicationContext applicationContext;
15 |
16 | @Bean
17 | public BeanMapper beanMapper() {
18 | BeanMapperBuilder bm = new BeanMapperBuilder()
19 | .addPackagePrefix(FakeApplicationConfig.class);
20 | if (applicationContext != null) {
21 | bm.addConverter(new IdToEntityBeanConverter(applicationContext));
22 | }
23 | return bm.build();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/converter/BeanMapperConverterAdapterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.converter;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertEquals;
7 |
8 | import io.beanmapper.BeanMapper;
9 | import io.beanmapper.config.BeanMapperBuilder;
10 | import io.beanmapper.spring.model.Person;
11 | import io.beanmapper.spring.model.PersonView;
12 |
13 | import org.junit.jupiter.api.Test;
14 | import org.springframework.core.convert.support.DefaultConversionService;
15 |
16 | public class BeanMapperConverterAdapterTest {
17 |
18 | @Test
19 | public void testConvert() {
20 | BeanMapper beanMapper = new BeanMapperBuilder().build();
21 | DefaultConversionService conversionService = new DefaultConversionService();
22 | conversionService.addConverter(new BeanMapperConverterAdapter(beanMapper));
23 | Person person = new Person();
24 | person.setName("Jan");
25 | PersonView personView = conversionService.convert(person, PersonView.class);
26 | assertEquals("Jan", personView.name);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/Fake.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import static jakarta.persistence.GenerationType.IDENTITY;
4 |
5 | import jakarta.persistence.Column;
6 | import jakarta.persistence.Entity;
7 | import jakarta.persistence.GeneratedValue;
8 | import jakarta.persistence.Id;
9 |
10 | import org.springframework.data.domain.Persistable;
11 |
12 | import com.fasterxml.jackson.annotation.JsonIgnore;
13 |
14 | @Entity
15 | public class Fake implements Persistable {
16 |
17 | @Id
18 | @GeneratedValue(strategy = IDENTITY)
19 | private Long id;
20 |
21 | @Column(name = "name")
22 | private String name;
23 |
24 | /**
25 | * {@inheritDoc}
26 | */
27 | @Override
28 | public Long getId() {
29 | return id;
30 | }
31 |
32 | public void setId(Long id) {
33 | this.id = id;
34 | }
35 |
36 | /**
37 | * {@inheritDoc}
38 | */
39 | @Override
40 | @JsonIgnore
41 | public boolean isNew() {
42 | return id == null;
43 | }
44 |
45 | public String getName() {
46 | return name;
47 | }
48 |
49 | public void setName(String name) {
50 | this.name = name;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/mockmvc/MockIdToEntityBeanConverter.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc;
2 |
3 | import io.beanmapper.BeanMapper;
4 | import io.beanmapper.core.BeanPropertyMatch;
5 | import io.beanmapper.core.converter.BeanConverter;
6 |
7 | import org.springframework.data.domain.Persistable;
8 | import org.springframework.data.repository.CrudRepository;
9 |
10 | public class MockIdToEntityBeanConverter implements BeanConverter {
11 |
12 | private final Class> targetClass;
13 |
14 | private final CrudRepository extends Persistable, Long> repository;
15 |
16 | public MockIdToEntityBeanConverter(CrudRepository extends Persistable, Long> repository, Class> targetClass) {
17 | this.repository = repository;
18 | this.targetClass = targetClass;
19 | }
20 |
21 | @Override
22 | public T convert(BeanMapper beanMapper, S source, Class targetClass, BeanPropertyMatch beanFieldMatch) {
23 | return targetClass.cast(repository.findById((Long)source).orElse(null));
24 | }
25 |
26 | @Override
27 | public boolean match(Class> sourceClass, Class> targetClass) {
28 | return sourceClass.equals(Long.class) && targetClass.equals(this.targetClass);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/converter/ConversionServiceBeanConverterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.converter;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertEquals;
7 | import static org.junit.jupiter.api.Assertions.assertTrue;
8 |
9 | import org.junit.jupiter.api.BeforeEach;
10 | import org.junit.jupiter.api.Test;
11 | import org.springframework.core.convert.ConversionService;
12 | import org.springframework.core.convert.support.DefaultConversionService;
13 |
14 | /**
15 | *
16 | *
17 | * @author Jeroen van Schagen
18 | * @since Jun 18, 2015
19 | */
20 | class ConversionServiceBeanConverterTest {
21 |
22 | private ConversionService conversionService;
23 |
24 | private ConversionServiceBeanConverter beanConverter;
25 |
26 | @BeforeEach
27 | void setUp() {
28 | conversionService = new DefaultConversionService();
29 | beanConverter = new ConversionServiceBeanConverter(conversionService);
30 | }
31 |
32 | @Test
33 | void testCanConvert() {
34 | assertTrue(beanConverter.match(String.class, Long.class));
35 | }
36 |
37 | @Test
38 | void testConvert() {
39 | assertEquals(Long.valueOf(1), beanConverter.convert(null, "1", Long.class, null));
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/EntityFinder.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web;
2 |
3 | import jakarta.persistence.EntityNotFoundException;
4 |
5 | /**
6 | * Provides a generic interface for custom entity finders. The entity finder is
7 | * used within MergedFormMethodArgumentResolver to fetch the entity.
8 | * @author Robert Bor
9 | */
10 | public interface EntityFinder {
11 |
12 | /**
13 | * Returns the entity on the basis of the entity class and its ID.
14 | * @param entityClass the class of the entity
15 | * @param id the ID of the entity
16 | * @return the entity if found
17 | * @throws jakarta.persistence.EntityNotFoundException if the repository or the entity
18 | * could not be found
19 | */
20 | T find(Long id, Class entityClass) throws EntityNotFoundException;
21 |
22 | /**
23 | * Returns the entity on the basis of the entity class and its ID bypassing the
24 | * Hibernate cache
25 | * @param entityClass the class of the entity
26 | * @param id the ID of the entity
27 | * @return the entity if found
28 | * @throws jakarta.persistence.EntityNotFoundException if the repository or the entity
29 | * could not be found
30 | */
31 | T findAndDetach(Long id, Class entityClass) throws EntityNotFoundException;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/flusher/JpaAfterClearFlusherTest.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.flusher;
2 |
3 | import static org.mockito.Mockito.doNothing;
4 | import static org.mockito.Mockito.verify;
5 |
6 | import jakarta.persistence.EntityManager;
7 |
8 | import io.beanmapper.BeanMapper;
9 | import io.beanmapper.config.BeanMapperBuilder;
10 |
11 | import org.junit.jupiter.api.Test;
12 | import org.junit.jupiter.api.extension.ExtendWith;
13 | import org.mockito.Mock;
14 | import org.mockito.junit.jupiter.MockitoExtension;
15 |
16 | @ExtendWith(MockitoExtension.class)
17 | public class JpaAfterClearFlusherTest {
18 |
19 | @Mock
20 | private EntityManager entityManager;
21 |
22 | @Test
23 | public void persistenceManagerFlushCalled() {
24 | doNothing().when(entityManager).flush();
25 |
26 | JpaAfterClearFlusher flusher = new JpaAfterClearFlusher(entityManager);
27 | CollSource source = new CollSource() {{
28 | items.add("A");
29 | }};
30 | CollTarget target = new CollTarget() {{
31 | items.add("B");
32 | }};
33 | BeanMapper beanMapper = new BeanMapperBuilder()
34 | .setFlushEnabled(true)
35 | .addAfterClearFlusher(flusher)
36 | .build();
37 | beanMapper.map(source, target);
38 |
39 | verify(entityManager).flush();
40 |
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/fakedomain/ContainingFakeController.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc.fakedomain;
2 |
3 | import jakarta.validation.Valid;
4 |
5 | import io.beanmapper.BeanMapper;
6 | import io.beanmapper.spring.web.MergedForm;
7 |
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.web.bind.annotation.RequestMapping;
10 | import org.springframework.web.bind.annotation.RequestMethod;
11 | import org.springframework.web.bind.annotation.RestController;
12 |
13 | @RestController
14 | @RequestMapping("/containing-fake")
15 | public class ContainingFakeController {
16 |
17 | @Autowired
18 | private ContainingFakeService containingFakeService;
19 |
20 | public BeanMapper beanMapper;
21 |
22 | @RequestMapping(method = RequestMethod.POST)
23 | public ContainingFakeResult create(@MergedForm(value = ContainingFakeForm.class) ContainingFake containingFake) {
24 | return beanMapper.map(containingFakeService.create(containingFake), ContainingFakeResult.class);
25 | }
26 |
27 | @RequestMapping(value = "validate", method = RequestMethod.POST)
28 | public ContainingFakeResult createValid(@Valid @MergedForm(value = ContainingFakeForm.class) ContainingFake containingFake) {
29 | return beanMapper.map(containingFakeService.create(containingFake), ContainingFakeResult.class);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/AbstractSpringTest.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring;
2 |
3 | import javax.sql.DataSource;
4 |
5 | import org.junit.jupiter.api.AfterEach;
6 | import org.junit.jupiter.api.extension.ExtendWith;
7 | import org.mockito.Mock;
8 | import org.mockito.junit.jupiter.MockitoExtension;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 | import org.springframework.jdbc.core.JdbcTemplate;
12 | import org.springframework.test.context.ContextConfiguration;
13 | import org.springframework.test.context.junit.jupiter.SpringExtension;
14 |
15 | /**
16 | * Base for Spring dependent tests.
17 | *
18 | * @author Jeroen van Schagen
19 | * @since Aug 24, 2015
20 | */
21 | @ExtendWith(MockitoExtension.class)
22 | @ExtendWith(SpringExtension.class)
23 | @ContextConfiguration(classes = { ApplicationConfig.class })
24 | @SpringBootTest
25 | public abstract class AbstractSpringTest {
26 |
27 | @Mock
28 | private JdbcTemplate jdbcTemplate;
29 |
30 | @AfterEach
31 | public void cleanUp() {
32 | jdbcTemplate.execute("TRUNCATE SCHEMA public AND COMMIT");
33 | }
34 |
35 | @Autowired
36 | public void setDataSource(DataSource dataSource) {
37 | jdbcTemplate = new JdbcTemplate(dataSource);
38 | }
39 |
40 | public JdbcTemplate getJdbcTemplate() {
41 | return jdbcTemplate;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/MergedForm.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.web;
5 |
6 | import java.lang.annotation.ElementType;
7 | import java.lang.annotation.Retention;
8 | import java.lang.annotation.RetentionPolicy;
9 | import java.lang.annotation.Target;
10 |
11 | /**
12 | * Capable of reading an input form and mapping this
13 | * into an existing/new entity. The entity is declared
14 | * as parameter in our handler mapping method.
15 | *
16 | * @since Nov 15, 2015
17 | */
18 | @Target({ ElementType.PARAMETER })
19 | @Retention(RetentionPolicy.RUNTIME)
20 | public @interface MergedForm {
21 |
22 | /**
23 | * Type of input form.
24 | * @return the input form class
25 | */
26 | Class> value();
27 |
28 | /**
29 | * When patch, we only map the provided properties
30 | * from our input form to the entity.
31 | * @return the patch
32 | */
33 | boolean patch() default false;
34 |
35 | /**
36 | * Entity identifier variable in our path mapping.
37 | * @return the identifier variable
38 | */
39 | String mergeId() default "";
40 |
41 | /**
42 | * Class types of the before-/afterMerge instances maintained in MergePair
43 | */
44 | Class> mergePairClass() default Object.class;
45 |
46 | /**
47 | * The name of the request part in the multipart form
48 | * @return the name of the request part in the multipart form
49 | */
50 | String multiPart() default "";
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/unproxy/HibernateAwareBeanUnproxyTest.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.unproxy;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 |
5 | import io.beanmapper.spring.model.Spoon;
6 | import io.beanmapper.spring.model.SpoonDrawerForm;
7 |
8 | import org.junit.jupiter.api.BeforeEach;
9 | import org.junit.jupiter.api.Test;
10 |
11 | class HibernateAwareBeanUnproxyTest {
12 |
13 | private HibernateAwareBeanUnproxy beanUnproxy;
14 |
15 | @BeforeEach
16 | void setUp() {
17 | this.beanUnproxy = new HibernateAwareBeanUnproxy();
18 | }
19 |
20 | @Test
21 | void unproxyHibernateProxy() {
22 | HibernateProxyContainer shopHibernateProxy = new HibernateProxyContainer();
23 | Object object = shopHibernateProxy.new GeneratedProxy();
24 | Class> unproxyClass = beanUnproxy.unproxy(object.getClass());
25 | assertEquals(Shop.class, unproxyClass);
26 | }
27 |
28 | @Test
29 | void testUnproxy_ShouldNotConsiderStaticNestedClassAHibernateProxy() {
30 | Object object = new SpoonDrawerForm.SpoonForm();
31 | Class> unproxyClass = beanUnproxy.unproxy(object.getClass());
32 | assertEquals(SpoonDrawerForm.SpoonForm.class, unproxyClass);
33 | }
34 |
35 | @Test
36 | void testUnproxy_ShouldReturnObjectUnchangedWhenNotAHibernateProxy() {
37 | Object object = new Spoon(true);
38 | Class> unproxyClass = beanUnproxy.unproxy(object.getClass());
39 | assertEquals(Spoon.class, unproxyClass);
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/converter/BeanMapperConverterAdapter.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.converter;
2 |
3 | import java.util.Collections;
4 | import java.util.Set;
5 |
6 | import io.beanmapper.BeanMapper;
7 |
8 | import org.springframework.core.convert.TypeDescriptor;
9 | import org.springframework.core.convert.converter.GenericConverter;
10 |
11 | /**
12 | * Adapter that allows the bean mapper to be used in
13 | * the spring conversion service.
14 | *
15 | * @author Jeroen van Schagen
16 | * @since Aug 21, 2015
17 | */
18 | public class BeanMapperConverterAdapter implements GenericConverter {
19 |
20 | /**
21 | * Delegate bean mapper.
22 | */
23 | private final BeanMapper beanMapper;
24 |
25 | /**
26 | * Construct a new instance.
27 | * @param beanMapper the bean mapper
28 | */
29 | public BeanMapperConverterAdapter(BeanMapper beanMapper) {
30 | this.beanMapper = beanMapper;
31 | }
32 |
33 | /**
34 | * {@inheritDoc}
35 | */
36 | @Override
37 | public Set getConvertibleTypes() {
38 | return Collections.singleton(new ConvertiblePair(Object.class, Object.class));
39 | }
40 |
41 | /**
42 | * {@inheritDoc}
43 | */
44 | @Override
45 | public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
46 | if (sourceType.getType().equals(targetType.getType())) {
47 | return source;
48 | }
49 | return beanMapper.map(source, targetType.getType());
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/converter/ConversionServiceBeanConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.converter;
5 |
6 | import io.beanmapper.BeanMapper;
7 | import io.beanmapper.core.BeanPropertyMatch;
8 | import io.beanmapper.core.converter.BeanConverter;
9 |
10 | import org.springframework.core.convert.ConversionService;
11 |
12 | /**
13 | * Spring based bean converter adapter. Makes use of Spring's
14 | * build-in conversion service.
15 | *
16 | * @author Jeroen van Schagen
17 | * @since Jun 18, 2015
18 | */
19 | public class ConversionServiceBeanConverter implements BeanConverter {
20 |
21 | /**
22 | * Performs type conversions in Spring.
23 | */
24 | private final ConversionService conversionService;
25 |
26 | /**
27 | * Construct a new {@link ConversionServiceBeanConverter}.
28 | * @param conversionService the converter delegate
29 | */
30 | public ConversionServiceBeanConverter(ConversionService conversionService) {
31 | this.conversionService = conversionService;
32 | }
33 |
34 | @Override
35 | public T convert(BeanMapper beanMapper, S source, Class targetClass, BeanPropertyMatch beanFieldMatch) {
36 | return conversionService.convert(source, targetClass);
37 | }
38 |
39 | /**
40 | * {@inheritDoc}
41 | */
42 | @Override
43 | public boolean match(Class> sourceClass, Class> targetClass) {
44 | return conversionService.canConvert(sourceClass, targetClass);
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/util/JsonUtil.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.util;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | import tools.jackson.core.JacksonException;
7 | import tools.jackson.databind.JsonNode;
8 | import tools.jackson.databind.ObjectMapper;
9 |
10 | /**
11 | * Utilities for working with JSON.
12 | *
13 | * @author Jeroen van Schagen
14 | * @since Nov 13, 2015
15 | */
16 | public class JsonUtil {
17 |
18 | /**
19 | * Retrieve the property names mentioned in a JSON content.
20 | *
21 | * @param json the JSON content
22 | * @param objectMapper the object mapper
23 | * @return set of the property names
24 | */
25 | public static Set getPropertyNamesFromJson(String json, ObjectMapper objectMapper) {
26 | try {
27 | JsonNode tree = objectMapper.readTree(json);
28 | return getPropertyNames(tree, "");
29 | } catch (JacksonException e) {
30 | throw new IllegalStateException("Could not retrieve property names from JSON.", e);
31 | }
32 | }
33 |
34 | private static Set getPropertyNames(JsonNode node, String base) {
35 | Set propertyNames = new HashSet<>();
36 | node.propertyNames().forEach(fieldName -> {
37 | String propertyName = isEmpty(base) ? fieldName : base + "." + fieldName;
38 | propertyNames.add(propertyName);
39 | propertyNames.addAll(getPropertyNames(node.get(fieldName), propertyName));
40 | });
41 | return propertyNames;
42 | }
43 |
44 | private static boolean isEmpty(String str) {
45 | return str == null || str.isEmpty();
46 | }
47 | }
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/Product.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | import java.util.List;
4 |
5 | public class Product {
6 |
7 | private Long id;
8 |
9 | private String name;
10 |
11 | private String upc;
12 |
13 | private String internalMemo;
14 |
15 | private List assets;
16 |
17 | private List artists;
18 |
19 | private Organization organization;
20 |
21 | public Long getId() {
22 | return id;
23 | }
24 |
25 | public void setId(Long id) {
26 | this.id = id;
27 | }
28 |
29 | public String getInternalMemo() {
30 | return internalMemo;
31 | }
32 |
33 | public void setInternalMemo(String internalMemo) {
34 | this.internalMemo = internalMemo;
35 | }
36 |
37 | public String getName() {
38 | return name;
39 | }
40 |
41 | public void setName(String name) {
42 | this.name = name;
43 | }
44 |
45 | public String getUpc() {
46 | return upc;
47 | }
48 |
49 | public void setUpc(String upc) {
50 | this.upc = upc;
51 | }
52 |
53 | public List getAssets() {
54 | return assets;
55 | }
56 |
57 | public void setAssets(List assets) {
58 | this.assets = assets;
59 | }
60 |
61 | public List getArtists() {
62 | return artists;
63 | }
64 |
65 | public void setArtists(List artists) {
66 | this.artists = artists;
67 | }
68 |
69 | public Organization getOrganization() {
70 | return organization;
71 | }
72 |
73 | public void setOrganization(Organization organization) {
74 | this.organization = organization;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/PageableMapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Collections;
8 | import java.util.List;
9 |
10 | import io.beanmapper.BeanMapper;
11 |
12 | import org.springframework.data.domain.Page;
13 | import org.springframework.data.domain.PageImpl;
14 | import org.springframework.data.domain.PageRequest;
15 | import org.springframework.data.domain.Pageable;
16 |
17 | /**
18 | * Mapping utilities for pages.
19 | *
20 | * @author Jeroen van Schagen
21 | * @since Nov 13, 2015
22 | */
23 | public class PageableMapper {
24 |
25 | /**
26 | * Private constructor to hide the implicit public constructor of
27 | * utility-class.
28 | */
29 | private PageableMapper() {}
30 |
31 | /**
32 | * Converts a page into the desired target type.
33 | *
34 | * @param source the source page
35 | * @param targetClass the target type
36 | * @param beanMapper the bean mapper used to perform mappings
37 | * @return the same page, but with result type
38 | */
39 | public static Page map(Page source, Class targetClass, BeanMapper beanMapper) {
40 | List transformed;
41 | if (source.hasContent()) {
42 | List content = new ArrayList<>(source.getContent());
43 | transformed = beanMapper.map(content, targetClass);
44 | } else {
45 | transformed = Collections.emptyList();
46 | }
47 | Pageable pageable = PageRequest.of(source.getNumber(), source.getSize(), source.getSort());
48 | return new PageImpl<>(transformed, pageable, source.getTotalElements());
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/WebRequestParameters.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web;
2 |
3 | import org.springframework.core.Conventions;
4 | import org.springframework.core.MethodParameter;
5 | import org.springframework.validation.BindingResult;
6 | import org.springframework.web.bind.WebDataBinder;
7 | import org.springframework.web.bind.support.WebDataBinderFactory;
8 | import org.springframework.web.context.request.NativeWebRequest;
9 | import org.springframework.web.method.support.ModelAndViewContainer;
10 |
11 | public class WebRequestParameters {
12 |
13 | private final MethodParameter parameter;
14 | private final ModelAndViewContainer mavContainer;
15 | private final NativeWebRequest webRequest;
16 | private final WebDataBinderFactory binderFactory;
17 |
18 | public WebRequestParameters(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest,
19 | WebDataBinderFactory binderFactory) {
20 | this.parameter = parameter;
21 | this.mavContainer = mavContainer;
22 | this.webRequest = webRequest;
23 | this.binderFactory = binderFactory;
24 | }
25 |
26 | public WebDataBinder createBinder(Object objectToValidate) throws Exception {
27 | String name = Conventions.getVariableNameForParameter(parameter);
28 | return binderFactory.createBinder(webRequest, objectToValidate, name);
29 | }
30 |
31 | public void setBindingResult(BindingResult bindingResult) {
32 | String name = Conventions.getVariableNameForParameter(parameter);
33 | mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, bindingResult);
34 | }
35 |
36 | public MethodParameter getParameter() {
37 | return parameter;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/mockmvc/MockEntityFinder.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import jakarta.persistence.EntityNotFoundException;
7 |
8 | import io.beanmapper.exceptions.BeanConstructException;
9 | import io.beanmapper.spring.exceptions.ClassExpectationNotRegisteredException;
10 | import io.beanmapper.spring.web.EntityFinder;
11 |
12 | import org.springframework.data.domain.Persistable;
13 | import org.springframework.data.repository.CrudRepository;
14 |
15 | public class MockEntityFinder implements EntityFinder {
16 |
17 | private final Map, CrudRepository extends Persistable, Long>> repositories = new HashMap<>();
18 |
19 | @Override
20 | public T find(Long id, Class entityClass) throws EntityNotFoundException, BeanConstructException {
21 | CrudRepository repository = (CrudRepository)repositories.get(entityClass);
22 | if (repository == null) {
23 | throw new BeanConstructException(entityClass, new ClassExpectationNotRegisteredException("No constructor found for " + entityClass.getSimpleName() +
24 | ". Make sure to register the class in addConverters.registerExpectation."));
25 | }
26 | return repository.findById(id).orElse(null);
27 | }
28 |
29 | @Override
30 | public T findAndDetach(Long id, Class entityClass) throws EntityNotFoundException, BeanConstructException {
31 | // Not supported, same as find
32 | return find(id, entityClass);
33 | }
34 |
35 | public void addRepository(CrudRepository extends Persistable, Long> repository, Class> entityClass) {
36 | repositories.put(entityClass, repository);
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/security/AbstractSpringSecuredCheck.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.security;
2 |
3 | import io.beanmapper.spring.exceptions.PrincipalIsNoInstanceOfUserDetailsException;
4 |
5 | import org.springframework.security.core.Authentication;
6 | import org.springframework.security.core.GrantedAuthority;
7 | import org.springframework.security.core.context.SecurityContextHolder;
8 | import org.springframework.security.core.userdetails.UserDetails;
9 |
10 | public abstract class AbstractSpringSecuredCheck {
11 |
12 | protected Object getPrincipal() {
13 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
14 | return authentication.getPrincipal();
15 | }
16 |
17 | protected UserDetails getUserDetails() {
18 | Object principal = getPrincipal();
19 | if (!(getPrincipal() instanceof UserDetails)) {
20 | throw new PrincipalIsNoInstanceOfUserDetailsException();
21 | }
22 | return (UserDetails)principal;
23 | }
24 |
25 | public boolean hasRole(String... roles) {
26 | if (hasNoRequiredRoles(roles)) {
27 | return true;
28 | }
29 | UserDetails userDetails = getUserDetails();
30 | for (String role : roles) {
31 | for (GrantedAuthority authority : userDetails.getAuthorities()) {
32 | if (hasRole(authority, role)) {
33 | return true;
34 | }
35 | }
36 | }
37 | return false;
38 | }
39 |
40 | private boolean hasRole(GrantedAuthority authority, String role) {
41 | String prefixedRole = "ROLE_" + role;
42 | return prefixedRole.equals(authority.getAuthority()) ||
43 | role.equals(authority.getAuthority());
44 | }
45 |
46 | private boolean hasNoRequiredRoles(String[] roles) {
47 | return roles.length == 0;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/MergePair.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web;
2 |
3 | import io.beanmapper.BeanMapper;
4 |
5 | public class MergePair {
6 |
7 | private T beforeMerge;
8 | private T afterMerge;
9 | private final BeanMapper beanMapper;
10 | private final EntityFinder entityFinder;
11 | private final Class> entityClass;
12 | private final MergedForm annotation;
13 |
14 | public MergePair(BeanMapper beanMapper, EntityFinder entityFinder, Class> entityClass, MergedForm annotation) {
15 | this.beanMapper = beanMapper;
16 | this.entityFinder = entityFinder;
17 | this.entityClass = entityClass;
18 | this.annotation = annotation;
19 | }
20 |
21 | public void initNew(Object source) {
22 | setAfterMerge(beanMapper.map(source, targetEntityClass()));
23 | }
24 |
25 | public void merge(Object source, Long id) {
26 | if (isMergePair()) {
27 | setBeforeMerge(entityFinder.findAndDetach(id, targetEntityClass()));
28 | }
29 | T target = entityFinder.find(id, targetEntityClass());
30 | setAfterMerge(beanMapper.map(source, target));
31 | }
32 |
33 | public T getBeforeMerge() {
34 | return beforeMerge;
35 | }
36 |
37 | public T getAfterMerge() {
38 | return afterMerge;
39 | }
40 |
41 | public Object result() {
42 | return isMergePair() ? this : getAfterMerge();
43 | }
44 |
45 | private boolean isMergePair() {
46 | return entityClass.equals(MergePair.class);
47 | }
48 |
49 | private Class targetEntityClass() {
50 | return isMergePair() ? (Class)annotation.mergePairClass() : (Class)entityClass;
51 | }
52 |
53 | private void setBeforeMerge(T beforeMerge) {
54 | this.beforeMerge = beforeMerge;
55 | }
56 |
57 | private void setAfterMerge(T afterMerge) {
58 | this.afterMerge = afterMerge;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/converter/IdToEntityBeanConverter.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.converter;
2 |
3 | import java.io.Serializable;
4 |
5 | import jakarta.persistence.EntityNotFoundException;
6 |
7 | import io.beanmapper.BeanMapper;
8 | import io.beanmapper.core.BeanPropertyMatch;
9 | import io.beanmapper.core.converter.BeanConverter;
10 |
11 | import org.springframework.context.ApplicationContext;
12 | import org.springframework.data.repository.CrudRepository;
13 | import org.springframework.data.repository.core.EntityInformation;
14 | import org.springframework.data.repository.support.Repositories;
15 |
16 | public class IdToEntityBeanConverter implements BeanConverter {
17 |
18 | private final Repositories repositories;
19 |
20 | public IdToEntityBeanConverter(ApplicationContext applicationContext) {
21 | this.repositories = new Repositories(applicationContext);
22 | }
23 |
24 | @Override
25 | public T convert(BeanMapper beanMapper, S source, Class targetClass, BeanPropertyMatch beanFieldMatch) {
26 | if (source == null) {
27 | return null;
28 | }
29 |
30 | CrudRepository repository = (CrudRepository) repositories.getRepositoryFor(targetClass).orElseThrow(() -> new EntityNotFoundException(
31 | "No repository found for " + targetClass.getName()
32 | ));
33 |
34 | return targetClass.cast(repository.findById(source).orElse(null));
35 | }
36 |
37 | /**
38 | * {@inheritDoc}
39 | */
40 | @Override
41 | public boolean match(Class> sourceClass, Class> targetClass) {
42 | if (targetClass.isAssignableFrom(sourceClass)) {
43 | return false;
44 | }
45 | if (!repositories.hasRepositoryFor(targetClass)) {
46 | return false;
47 | }
48 | // No need for a null check. Repository#getEntityInformation fails if null.
49 | return sourceClass.equals(repositories.getEntityInformationFor(targetClass).getIdType());
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/SpringDataEntityFinder.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web;
2 |
3 | import jakarta.persistence.EntityManager;
4 | import jakarta.persistence.EntityNotFoundException;
5 |
6 | import org.springframework.context.ApplicationContext;
7 | import org.springframework.data.repository.CrudRepository;
8 | import org.springframework.data.repository.support.Repositories;
9 |
10 | /**
11 | * The default implementation is based on the Repositories class of Spring Data. It
12 | * first looks up the repository. If found, it then calls findOne on the repository.
13 | * @author Robert Bor
14 | */
15 | public class SpringDataEntityFinder implements EntityFinder {
16 |
17 | private final Repositories repositories;
18 |
19 | private final EntityManager entityManager;
20 |
21 | public SpringDataEntityFinder(ApplicationContext applicationContext, EntityManager entityManager) {
22 | this.repositories = new Repositories(applicationContext);
23 | this.entityManager = entityManager;
24 | }
25 |
26 | /**
27 | * {@inheritDoc}
28 | */
29 | @Override
30 | public T findAndDetach(Long id, Class entityClass) throws EntityNotFoundException {
31 | T entity = find(id, entityClass);
32 | entityManager.detach(entity);
33 | return entity;
34 | }
35 |
36 | /**
37 | * {@inheritDoc}
38 | */
39 | @Override
40 | @SuppressWarnings("unchecked")
41 | public T find(Long id, Class entityClass) throws EntityNotFoundException {
42 | CrudRepository repository =
43 | (CrudRepository) repositories.getRepositoryFor(entityClass)
44 | .orElseThrow(() -> new EntityNotFoundException("No repository found for " + entityClass.getName())
45 | );
46 |
47 | return repository.findById(id).orElseThrow(() -> new EntityNotFoundException(
48 | "Entity with ID " + id + "was not found in repository " + repository.getClass().getName())
49 | );
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/FakeController.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc;
2 |
3 | import io.beanmapper.BeanMapper;
4 | import io.beanmapper.spring.web.MergedForm;
5 | import io.beanmapper.spring.web.mockmvc.fakedomain.Fake;
6 | import io.beanmapper.spring.web.mockmvc.fakedomain.FakeForm;
7 | import io.beanmapper.spring.web.mockmvc.fakedomain.FakeResult;
8 | import io.beanmapper.spring.web.mockmvc.fakedomain.FakeService;
9 |
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.web.bind.annotation.DeleteMapping;
12 | import org.springframework.web.bind.annotation.GetMapping;
13 | import org.springframework.web.bind.annotation.PathVariable;
14 | import org.springframework.web.bind.annotation.PostMapping;
15 | import org.springframework.web.bind.annotation.PutMapping;
16 | import org.springframework.web.bind.annotation.RequestMapping;
17 | import org.springframework.web.bind.annotation.RestController;
18 |
19 | @RestController
20 | @RequestMapping("/fake")
21 | public class FakeController {
22 |
23 | @Autowired
24 | private FakeService fakeService;
25 |
26 | // Made public due to issues
27 | public BeanMapper beanMapper;
28 |
29 | @GetMapping(value = "/{fake}")
30 | public FakeResult read(@PathVariable("fake") Fake fake) {
31 | return beanMapper.map(fakeService.read(fake), FakeResult.class);
32 | }
33 |
34 | @PostMapping
35 | public FakeResult create(@MergedForm(value = FakeForm.class) Fake fake) {
36 | return beanMapper.map(fakeService.create(fake), FakeResult.class);
37 | }
38 |
39 | @PutMapping(value = "/{id}")
40 | public FakeResult update(@MergedForm(mergeId = "id", value = FakeForm.class) Fake fake) {
41 | return beanMapper.map(fakeService.update(fake), FakeResult.class);
42 | }
43 |
44 | @DeleteMapping(value = "/{fake}")
45 | public FakeResult delete(@PathVariable("fake") Fake fake) {
46 | return beanMapper.map(fakeService.delete(fake), FakeResult.class);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/EntityFinderTest.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 | import static org.junit.jupiter.api.Assertions.assertNotNull;
5 | import static org.mockito.Mockito.when;
6 |
7 | import java.util.Optional;
8 |
9 | import jakarta.persistence.EntityNotFoundException;
10 |
11 | import io.beanmapper.spring.AbstractSpringTest;
12 | import io.beanmapper.spring.model.Person;
13 | import io.beanmapper.spring.model.PersonRepository;
14 |
15 | import org.junit.jupiter.api.Test;
16 | import org.junit.jupiter.api.extension.ExtendWith;
17 | import org.mockito.Mock;
18 | import org.mockito.junit.jupiter.MockitoExtension;
19 | import org.springframework.beans.factory.annotation.Autowired;
20 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
21 |
22 | @ExtendWith(MockitoExtension.class)
23 | public class EntityFinderTest extends AbstractSpringTest {
24 |
25 | @Mock
26 | private PersonRepository personRepository;
27 |
28 | @Test
29 | public void find() {
30 | Person person = new Person();
31 | person.setName("Henk");
32 | person.setCity("Lisse");
33 | person.setId(42L);
34 |
35 | when(this.personRepository.findById(person.getId())).thenReturn(Optional.of(person));
36 |
37 | EntityFinder entityFinder = new EntityFinder() {
38 |
39 | @Override
40 | public T find(Long id, Class entityClass) throws EntityNotFoundException {
41 | return (T)personRepository.findById(id).orElse(null);
42 | }
43 |
44 | @Override
45 | public T findAndDetach(Long id, Class entityClass) throws EntityNotFoundException {
46 | return find(id, entityClass);
47 | }
48 |
49 | };
50 |
51 | Person foundPerson = entityFinder.find(person.getId(), Person.class);
52 | assertNotNull(foundPerson);
53 | assertEquals("Henk", foundPerson.getName());
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/model/Person.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import jakarta.persistence.CollectionTable;
7 | import jakarta.persistence.Column;
8 | import jakarta.persistence.ElementCollection;
9 | import jakarta.persistence.Entity;
10 | import jakarta.persistence.EnumType;
11 | import jakarta.persistence.Enumerated;
12 | import jakarta.persistence.FetchType;
13 | import jakarta.validation.constraints.NotNull;
14 |
15 | @Entity
16 | public class Person extends BaseEntity {
17 |
18 | @NotNull
19 | private String name;
20 |
21 | private String street;
22 |
23 | private String houseNumber;
24 |
25 | private String city;
26 |
27 | private String bankAccount;
28 |
29 | @ElementCollection(fetch = FetchType.EAGER)
30 | @CollectionTable(name = "owner_tag")
31 | @Enumerated(EnumType.STRING)
32 | @Column(name = "tag")
33 | private List tags = new ArrayList<>();
34 |
35 | public String getName() {
36 | return name;
37 | }
38 |
39 | public void setName(String name) {
40 | this.name = name;
41 | }
42 |
43 | public String getStreet() {
44 | return street;
45 | }
46 |
47 | public void setStreet(String street) {
48 | this.street = street;
49 | }
50 |
51 | public String getHouseNumber() {
52 | return houseNumber;
53 | }
54 |
55 | public void setHouseNumber(String houseNumber) {
56 | this.houseNumber = houseNumber;
57 | }
58 |
59 | public String getCity() {
60 | return city;
61 | }
62 |
63 | public void setCity(String city) {
64 | this.city = city;
65 | }
66 |
67 | public String getBankAccount() {
68 | return bankAccount;
69 | }
70 |
71 | public void setBankAccount(String bankAccount) {
72 | this.bankAccount = bankAccount;
73 | }
74 |
75 | public List getTags() {
76 | return tags;
77 | }
78 |
79 | public void setTags(List tags) {
80 | this.tags = tags;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/mockmvc/AbstractControllerTest.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc;
2 |
3 | import java.util.Collections;
4 |
5 | import io.beanmapper.BeanMapper;
6 | import io.beanmapper.spring.AbstractSpringTest;
7 | import io.beanmapper.spring.web.mockmvc.fakedomain.FakeApplicationConfig;
8 | import io.beanmapper.spring.web.mockmvc.fakedomain.FakeWebMvcConfig;
9 |
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
12 | import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
13 | import org.springframework.data.domain.Persistable;
14 | import org.springframework.data.repository.CrudRepository;
15 | import org.springframework.format.support.FormattingConversionService;
16 | import org.springframework.test.web.servlet.MockMvc;
17 | import org.springframework.test.web.servlet.setup.MockMvcBuilders;
18 |
19 | @AutoConfigureMockMvc
20 | @EnableAutoConfiguration
21 | public class AbstractControllerTest extends AbstractSpringTest {
22 |
23 | private FakeWebMvcConfig config = new FakeWebMvcConfig();
24 |
25 | @Autowired
26 | protected MockMvc webClient;
27 |
28 | protected MockMvcBeanMapper mockMvcBeanMapper;
29 |
30 | protected void initWebClient(Object controller) {
31 |
32 | this.mockMvcBeanMapper = new MockMvcBeanMapper(
33 | new FormattingConversionService(),
34 | Collections.singletonList(config.structuredJsonMessageConverter()),
35 | new FakeApplicationConfig().beanMapper()
36 | );
37 | }
38 |
39 | public void createWebClient(Object controller) {
40 | this.webClient = MockMvcBuilders.standaloneSetup(controller)
41 | .setMessageConverters(config.structuredJsonMessageConverter())
42 | .setCustomArgumentResolvers(mockMvcBeanMapper.createHandlerMethodArgumentResolvers())
43 | .setConversionService(mockMvcBeanMapper.getConversionService())
44 | .build();
45 | }
46 |
47 | public BeanMapper beanMapper() {
48 | return mockMvcBeanMapper.getBeanMapper();
49 | }
50 |
51 | public void registerRepository(CrudRepository repository, Class entityClass) {
52 | mockMvcBeanMapper.registerRepository(repository, entityClass);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/mockmvc/MockMvcBeanMapper.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web.mockmvc;
2 |
3 | import java.util.List;
4 |
5 | import io.beanmapper.BeanMapper;
6 | import io.beanmapper.spring.web.MergedFormMethodArgumentResolver;
7 |
8 | import org.springframework.data.domain.Persistable;
9 | import org.springframework.data.repository.CrudRepository;
10 | import org.springframework.format.support.FormattingConversionService;
11 | import org.springframework.http.converter.HttpMessageConverter;
12 | import org.springframework.web.method.support.HandlerMethodArgumentResolver;
13 |
14 | public class MockMvcBeanMapper {
15 |
16 | private final FormattingConversionService conversionService;
17 |
18 | private final List> messageConverters;
19 |
20 | private BeanMapper beanMapper;
21 |
22 | private MockEntityFinder mockEntityFinder = new MockEntityFinder();
23 |
24 | public MockMvcBeanMapper(FormattingConversionService conversionService,
25 | List> messageConverters,
26 | BeanMapper beanMapper) {
27 | this.conversionService = conversionService;
28 | this.messageConverters = messageConverters;
29 | this.beanMapper = beanMapper.wrap().build();
30 | }
31 |
32 | public > void registerRepository(CrudRepository repository, Class entityClass) {
33 |
34 | // Add a converter for the target class to the generic conversion service
35 | conversionService.addConverter(String.class, entityClass, new MockEntityConverter<>(repository));
36 |
37 | // Add a BeanConverter for the target class to the BeanMapper
38 | beanMapper = beanMapper.wrap().addConverter(new MockIdToEntityBeanConverter(repository, entityClass)).build();
39 |
40 | // Add the repository to the MockEntityFinder
41 | mockEntityFinder.addRepository(repository, entityClass);
42 | }
43 |
44 | public HandlerMethodArgumentResolver[] createHandlerMethodArgumentResolvers() {
45 | return new HandlerMethodArgumentResolver[] {
46 | new MergedFormMethodArgumentResolver(messageConverters, beanMapper, mockEntityFinder)
47 | };
48 | }
49 |
50 | public FormattingConversionService getConversionService() {
51 | return this.conversionService;
52 | }
53 |
54 | public BeanMapper getBeanMapper() {
55 | return beanMapper;
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/PageableMapperTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertEquals;
7 | import static org.junit.jupiter.api.Assertions.assertNotNull;
8 |
9 | import java.util.Arrays;
10 |
11 | import io.beanmapper.BeanMapper;
12 | import io.beanmapper.config.BeanMapperBuilder;
13 | import io.beanmapper.spring.model.Person;
14 | import io.beanmapper.spring.model.PersonForm;
15 |
16 | import org.junit.jupiter.api.Test;
17 | import org.springframework.data.domain.Page;
18 | import org.springframework.data.domain.PageImpl;
19 | import org.springframework.data.domain.PageRequest;
20 | import org.springframework.data.domain.Pageable;
21 | import org.springframework.data.domain.Sort;
22 |
23 | public class PageableMapperTest {
24 |
25 | private final Pageable pageable = PageRequest.of(0, 10, Sort.by("id"));
26 |
27 | private BeanMapper beanMapper;
28 |
29 | {
30 | beanMapper = new BeanMapperBuilder()
31 | .addPackagePrefix(ApplicationConfig.class)
32 | .build();
33 | }
34 |
35 | @Test
36 | public void testMap() {
37 | PersonForm form = new PersonForm();
38 | form.name = "Henk";
39 |
40 | Page source = new PageImpl(Arrays.asList(form), pageable, 1);
41 | Page target = PageableMapper.map(source, Person.class, beanMapper);
42 |
43 | assertNotNull(target);
44 | assertEquals(pageable.getPageNumber(), target.getNumber());
45 | assertEquals(pageable.getPageSize(), target.getSize());
46 | assertEquals(pageable.getSort(), target.getSort());
47 | assertEquals(1, target.getTotalElements());
48 |
49 | Person person = target.getContent().get(0);
50 | assertEquals(Person.class, person.getClass());
51 | assertEquals("Henk", person.getName());
52 | }
53 |
54 | @Test
55 | public void testMapEmpty() {
56 | Page source = new PageImpl(Arrays. asList(), pageable, 0);
57 | Page target = PageableMapper.map(source, Person.class, beanMapper);
58 |
59 | assertNotNull(target);
60 | assertEquals(pageable.getPageNumber(), target.getNumber());
61 | assertEquals(pageable.getPageSize(), target.getSize());
62 | assertEquals(pageable.getSort(), target.getSort());
63 | assertEquals(0, target.getTotalElements());
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/converter/IdToEntityBeanConverterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.converter;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertEquals;
7 | import static org.junit.jupiter.api.Assertions.assertFalse;
8 | import static org.junit.jupiter.api.Assertions.assertNull;
9 | import static org.junit.jupiter.api.Assertions.assertTrue;
10 |
11 | import io.beanmapper.spring.AbstractSpringTest;
12 | import io.beanmapper.spring.model.Artist;
13 | import io.beanmapper.spring.model.Asset;
14 | import io.beanmapper.spring.model.Person;
15 | import io.beanmapper.spring.model.PersonRepository;
16 |
17 | import org.junit.jupiter.api.BeforeEach;
18 | import org.junit.jupiter.api.Test;
19 | import org.springframework.beans.factory.annotation.Autowired;
20 | import org.springframework.context.ApplicationContext;
21 |
22 | public class IdToEntityBeanConverterTest extends AbstractSpringTest {
23 |
24 | @Autowired
25 | private ApplicationContext applicationContext;
26 |
27 | @Autowired
28 | private PersonRepository personRepository;
29 |
30 | private IdToEntityBeanConverter beanConverter;
31 |
32 | @BeforeEach
33 | public void setUp() {
34 | beanConverter = new IdToEntityBeanConverter(applicationContext);
35 | }
36 |
37 | @Test
38 | public void testCanConvert() {
39 | assertTrue(beanConverter.match(Long.class, Person.class));
40 | }
41 |
42 | @Test
43 | public void testCannotConvertInvalidSource() {assertFalse(beanConverter.match(String.class, Person.class));
44 | }
45 |
46 | @Test
47 | public void testCannotConvertInvalidTarget() {
48 | assertFalse(beanConverter.match(Long.class, Asset.class));
49 | }
50 |
51 | @Test
52 | public void testConvert() {
53 | Person person = new Person();
54 | person.setName("Henk");
55 | personRepository.save(person);
56 |
57 | assertEquals(person.getId(), ((Person) beanConverter.convert(null, person.getId(), Person.class, null)).getId());
58 | }
59 |
60 | @Test
61 | public void testSameClassNoMatch() {
62 | Person person = new Person();
63 | person.setName("Henk");
64 | assertFalse(beanConverter.match(person.getClass(), Person.class));
65 | }
66 |
67 | @Test
68 | public void noRepoForArtist() {
69 | assertFalse(beanConverter.match(Long.class, Artist.class));
70 | }
71 |
72 | @Test
73 | public void testConvertNull() {
74 | assertNull(beanConverter.convert(null, null, Person.class, null));
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/PersonController.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.web;
5 |
6 | import jakarta.validation.Valid;
7 |
8 | import io.beanmapper.spring.Lazy;
9 | import io.beanmapper.spring.model.Person;
10 | import io.beanmapper.spring.model.PersonForm;
11 |
12 | import org.springframework.stereotype.Controller;
13 | import org.springframework.web.bind.annotation.PutMapping;
14 | import org.springframework.web.bind.annotation.RequestMapping;
15 | import org.springframework.web.bind.annotation.RequestMethod;
16 | import org.springframework.web.bind.annotation.RequestPart;
17 | import org.springframework.web.bind.annotation.ResponseBody;
18 | import org.springframework.web.multipart.MultipartFile;
19 |
20 | @Controller
21 | @RequestMapping("/person")
22 | public class PersonController {
23 |
24 | @RequestMapping(method = RequestMethod.POST)
25 | @ResponseBody
26 | public Person create(@MergedForm(PersonForm.class) Person person) {
27 | return person;
28 | }
29 |
30 | @RequestMapping(value = "/query-param", method = RequestMethod.PUT)
31 | @ResponseBody
32 | public Person updateMergeIdInQueryParam(@MergedForm(value = PersonForm.class, mergeId = "id") Person person) {
33 | return person;
34 | }
35 |
36 | @RequestMapping(value = "/{id}/no-patch", method = RequestMethod.PUT)
37 | @ResponseBody
38 | public Person updateNoPatch(@MergedForm(value = PersonForm.class, mergeId = "id") Person person) {
39 | return person;
40 | }
41 |
42 | @RequestMapping(value = "/{id}/patch", method = RequestMethod.PUT)
43 | @ResponseBody
44 | public Person updatePatch(@MergedForm(value = PersonForm.class, patch = true, mergeId = "id") Person person) {
45 | return person;
46 | }
47 |
48 | @PutMapping("/{id}/lazy")
49 | @ResponseBody
50 | public Person updateLazy(@Valid @MergedForm(value = PersonForm.class, mergeId = "id") Lazy person) throws Exception {
51 | return person.get();
52 | }
53 |
54 | @RequestMapping(value = "/{id}/multipart", method = RequestMethod.POST)
55 | @ResponseBody
56 | public Person updateForMultipart(
57 | @Valid @MergedForm(value = PersonForm.class, mergeId = "id", multiPart = "personForm") Person person,
58 | @RequestPart(value = "photo", required = false) MultipartFile photo) {
59 | return person;
60 | }
61 |
62 | @RequestMapping(value = "/{id}/pair", method = RequestMethod.PUT)
63 | @ResponseBody
64 | public MergePair updateReturnPair(@MergedForm(value = PersonForm.class, mergeId = "id", mergePairClass = Person.class) MergePair personPair) {
65 | return personPair;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/test/java/io/beanmapper/spring/web/SpringDataEntityFinderTest.java:
--------------------------------------------------------------------------------
1 | package io.beanmapper.spring.web;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
5 | import static org.junit.jupiter.api.Assertions.assertNotNull;
6 | import static org.junit.jupiter.api.Assertions.assertThrows;
7 |
8 | import jakarta.persistence.EntityManager;
9 | import jakarta.persistence.EntityNotFoundException;
10 | import jakarta.persistence.PersistenceContext;
11 |
12 | import io.beanmapper.BeanMapper;
13 | import io.beanmapper.spring.AbstractSpringTest;
14 | import io.beanmapper.spring.model.Person;
15 | import io.beanmapper.spring.model.PersonRepository;
16 |
17 | import org.junit.jupiter.api.Test;
18 | import org.springframework.beans.factory.annotation.Autowired;
19 | import org.springframework.boot.test.context.SpringBootTest;
20 | import org.springframework.context.ApplicationContext;
21 | import org.springframework.transaction.annotation.Transactional;
22 |
23 | @SpringBootTest
24 | public class SpringDataEntityFinderTest extends AbstractSpringTest {
25 |
26 | @Autowired
27 | private ApplicationContext applicationContext;
28 |
29 | @PersistenceContext
30 | private EntityManager entityManager;
31 |
32 | @Autowired
33 | private PersonRepository personRepository;
34 |
35 | @Test
36 | public void find() {
37 | Person person = new Person();
38 | person.setName("Henk");
39 | person.setCity("Lisse");
40 | person = personRepository.save(person);
41 |
42 | EntityFinder entityFinder = new SpringDataEntityFinder(applicationContext, entityManager);
43 | Person foundPerson = (Person) entityFinder.find(person.getId(), Person.class);
44 | assertNotNull(foundPerson);
45 | assertEquals("Henk", foundPerson.getName());
46 | }
47 |
48 | @Test
49 | @Transactional
50 | public void findAndDetach() {
51 | Person person = new Person();
52 | person.setName("Henk");
53 | person.setCity("Lisse");
54 | person = personRepository.save(person);
55 |
56 | EntityFinder entityFinder = new SpringDataEntityFinder(applicationContext, entityManager);
57 | Person person1 = entityFinder.find(person.getId(), Person.class);
58 | Person person2 = entityFinder.find(person.getId(), Person.class);
59 | assertEquals(person1, person2);
60 |
61 | person1 = entityFinder.findAndDetach(person.getId(), Person.class);
62 | person2 = entityFinder.find(person.getId(), Person.class);
63 |
64 | assertNotEquals(person1, person2);
65 | }
66 |
67 | @Test
68 | public void noRepository() {
69 | EntityFinder entityFinder = new SpringDataEntityFinder(applicationContext, entityManager);
70 | assertThrows(EntityNotFoundException.class, () -> entityFinder.find(42L, BeanMapper.class));
71 | }
72 |
73 | @Test
74 | public void entityNotFound() {
75 | EntityFinder entityFinder = new SpringDataEntityFinder(applicationContext, entityManager);
76 | assertThrows(EntityNotFoundException.class, () -> entityFinder.find(42L, Person.class));
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/io/beanmapper/spring/web/converter/StructuredJsonMessageConverter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * (C) 2014 42 bv (www.42.nl). All rights reserved.
3 | */
4 | package io.beanmapper.spring.web.converter;
5 |
6 | import static java.nio.charset.StandardCharsets.UTF_8;
7 |
8 | import java.io.ByteArrayInputStream;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.util.List;
12 | import java.util.Set;
13 |
14 | import io.beanmapper.spring.util.JsonUtil;
15 |
16 | import org.springframework.http.HttpHeaders;
17 | import org.springframework.http.HttpInputMessage;
18 | import org.springframework.http.HttpOutputMessage;
19 | import org.springframework.http.MediaType;
20 | import org.springframework.http.converter.HttpMessageConverter;
21 | import org.springframework.http.converter.HttpMessageNotReadableException;
22 | import org.springframework.http.converter.HttpMessageNotWritableException;
23 | import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
24 |
25 | /**
26 | * Wraps the default Jackson message converter with read
27 | * functionality that returns both the message and property
28 | * names.
29 | *
30 | * @author Jeroen van Schagen
31 | * @since Nov 25, 2015
32 | */
33 | public class StructuredJsonMessageConverter implements HttpMessageConverter