Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/src/test/java/io/beanmapper/BeanCollectionExample.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ public class BeanCollectionExample {
@Test
void mapCollectionWithConstruct() {
Source source = new Source();
source.items = new LinkedHashSet<Person>();
source.items = new LinkedHashSet<>();
source.items.add(new Person(1L, "Henk", 42));
source.items.add(new Person(2L, "Piet", 18));
source.items.add(new Person(3L, "Gijs", 67));

TargetWithConstruct target = new TargetWithConstruct();
target.items = new ArrayList<PersonResult>();
target.items = new ArrayList<>();
target.items.add(new PersonResult("Kees", 13));
target.items.add(new PersonResult("Klaas", 24));

Expand All @@ -40,13 +40,13 @@ void mapCollectionWithConstruct() {
@Test
void mapCollectionWithReuse() {
Source source = new Source();
source.items = new LinkedHashSet<Person>();
source.items = new LinkedHashSet<>();
source.items.add(new Person(1L, "Henk", 42));
source.items.add(new Person(2L, "Piet", 18));
source.items.add(new Person(3L, "Gijs", 67));

TargetWithReuse target = new TargetWithReuse();
target.items = new ArrayList<PersonResult>();
target.items = new ArrayList<>();
target.items.add(new PersonResult("Kees", 13));
target.items.add(new PersonResult("Klaas", 24));

Expand All @@ -64,13 +64,13 @@ void mapCollectionWithReuse() {
@Test
void mapCollectionWithClear() {
Source source = new Source();
source.items = new LinkedHashSet<Person>();
source.items = new LinkedHashSet<>();
source.items.add(new Person(1L, "Henk", 42));
source.items.add(new Person(2L, "Piet", 18));
source.items.add(new Person(3L, "Gijs", 67));

TargetWithClear target = new TargetWithClear();
target.items = new ArrayList<PersonResult>();
target.items = new ArrayList<>();
target.items.add(new PersonResult("Kees", 13));
target.items.add(new PersonResult("Klaas", 24));

Expand Down
46 changes: 21 additions & 25 deletions src/main/java/io/beanmapper/BeanMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,16 @@
* objects. Once that has been determined, the applicable properties will be copied from
* source to target.
*/
public final class BeanMapper {
public record BeanMapper(Configuration configuration) {

private final Configuration configuration;

public BeanMapper(Configuration configuration) {
this.configuration = configuration;
}

private <S> void addDiagnosticsNode(S source) {
@SuppressWarnings("unchecked")
private <S, T> void addDiagnosticsNode(S source) {
if (configuration instanceof DiagnosticsConfiguration dc && dc.isInDiagnosticsMode()) {
if (dc.getParentConfiguration().orElse(null) instanceof DiagnosticsConfigurationImpl dci) {
dci.getBeanMapperDiagnostics().ifPresent(bd -> bd.getDiagnostics().clear());
}
Class<S> sourceClass = source != null ? (Class<S>) configuration.getBeanUnproxy().unproxy(source.getClass()) : (Class<S>) Void.class;
DiagnosticsNode<?, ?> node = getsDiagnosticsNode(source, sourceClass);
DiagnosticsNode<S, T> node = getsDiagnosticsNode(source, sourceClass);
dc.setBeanMapperDiagnostics(node);
if (configuration instanceof OverrideConfiguration) {
dc.getParentConfiguration()
Expand All @@ -52,13 +47,15 @@ private <S> void addDiagnosticsNode(S source) {
}
}

private <S> DiagnosticsNode<?, ?> getsDiagnosticsNode(S source, Class<S> sourceClass) {
DiagnosticsNode<?, ?> node = new MappingDiagnosticsNode<S, Object>(sourceClass, configuration.getTargetClass());
@SuppressWarnings({ "unchecked", "rawtypes" })
private <S, T> DiagnosticsNode<S, T> getsDiagnosticsNode(S source, Class<S> sourceClass) {
DiagnosticsNode<S, T> node = new MappingDiagnosticsNode<>(sourceClass, configuration.getTargetClass());
if (source instanceof Collection<?>) {
node = new CollectionMappingDiagnosticNode<>(source, sourceClass, configuration.getPreferredCollectionClass(), configuration.getTargetClass());
}
if (source instanceof Map<?, ?>) {
node = new MapMappingDiagnosticsNode<>((Map) source, (Class<Map>) sourceClass, configuration.getPreferredCollectionClass(), configuration.getTargetClass());
if (source instanceof Map<?, ?> map) {
node = new MapMappingDiagnosticsNode<>(map, (Class<Map>) sourceClass, configuration.getPreferredCollectionClass(),
configuration.getTargetClass());
}
return node;
}
Expand All @@ -67,7 +64,7 @@ public <S, T> T map(S source) {
addDiagnosticsNode(source);
if (source == null && !configuration.getUseNullValue()) {
// noinspection unchecked
return (T) this.getConfiguration().getDefaultValueForClass(this.getConfiguration().getTargetClass());
return (T) this.configuration().getDefaultValueForClass(this.configuration().getTargetClass());
}
T result = MapStrategyType.getStrategy(this, configuration).map(source);
if (this.configuration.getParentConfiguration().orElseThrow() instanceof DiagnosticsConfigurationImpl dc) {
Expand Down Expand Up @@ -101,6 +98,7 @@ public <S, T> T map(S source, T target) {
* @param <T> the instance to which the properties get copied
* @return the optional target instance containing all applicable properties
*/
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public <S, T> Optional<T> map(Optional<S> source, Class<T> targetClass) {
if (source.orElse(null) instanceof Optional<?> optional && !targetClass.isInstance(Optional.class)) {
return this.map(optional, targetClass);
Expand All @@ -122,15 +120,12 @@ public <S, T> Optional<T> map(Optional<S> source, Class<T> targetClass) {
* @return The result of the mapping.
*/
public <S, P extends ParameterizedType> Object map(S source, P target) {
if (source instanceof Collection<?> collection) {
return this.map(collection, (Class<?>) target.getActualTypeArguments()[0]);
} else if (source instanceof Map<?, ?> map) {
return this.map(map, (Class<?>) target.getActualTypeArguments()[1]);
} else if (source instanceof Optional<?> optional) {
return this.map(optional, (Class<?>) target.getActualTypeArguments()[0]);
} else {
return this.map(source, (Class<?>) target.getRawType());
}
return switch (source) {
case Collection<?> collection -> this.map(collection, (Class<?>) target.getActualTypeArguments()[0]);
case Map<?, ?> map -> this.map(map, (Class<?>) target.getActualTypeArguments()[1]);
case Optional<?> optional -> this.map(optional, (Class<?>) target.getActualTypeArguments()[0]);
default -> this.map(source, (Class<?>) target.getRawType());
};
}

/**
Expand Down Expand Up @@ -158,6 +153,7 @@ public <S, T> T map(S source, Class<T> targetClass) {
* @param <T> The type of the elements in the target array.
* @return A newly constructed array of the type of the target class.
*/
@SuppressWarnings("unchecked")
public <S, T> T[] map(S[] sourceArray, Class<T> targetClass) {
return Arrays.stream(sourceArray)
.map(element -> this.wrap().setConverterChoosable(true).build().map(element, targetClass))
Expand Down Expand Up @@ -249,7 +245,7 @@ public BeanMapperBuilder wrap(DiagnosticsDetailLevel detailLevel) {
return new BeanMapperBuilder(configuration, detailLevel);
}

public Configuration getConfiguration() {
return configuration;
public static BeanMapperBuilder builder() {
return new BeanMapperBuilder();
}
}
4 changes: 2 additions & 2 deletions src/main/java/io/beanmapper/annotations/BeanCollection.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
* type will be used by BeanMapper to pass the target class type.
* @return the class type of a target element collection
*/
Class elementType() default void.class;
Class<?> elementType() default void.class;

/**
* Determines how BeanMapper must deal with the target collection. The default option
Expand All @@ -40,7 +40,7 @@
* instead of the default one provided by the collection handler
* @return the class to instantiate instead of the one provided by the collection handler
*/
Class preferredCollectionClass() default void.class;
Class<?> preferredCollectionClass() default void.class;

/**
* When usage is CLEAR and the target collection is being managed by, eg, Hibernate's
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/io/beanmapper/config/BeanMapperBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

public class BeanMapperBuilder {

private static final List<CollectionHandler> DEFAULT_COLLECTION_HANDLERS =
private static final List<CollectionHandler<?>> DEFAULT_COLLECTION_HANDLERS =
List.of(
new MapCollectionHandler(),
new SetCollectionHandler(),
Expand All @@ -45,7 +45,7 @@ public class BeanMapperBuilder {

private final List<BeanConverter> customBeanConverters = new ArrayList<>();

private final List<CollectionHandler> customCollectionHandlers = new ArrayList<>();
private final List<CollectionHandler<?>> customCollectionHandlers = new ArrayList<>();

public BeanMapperBuilder() {
this.configuration = new CoreConfiguration();
Expand Down Expand Up @@ -79,7 +79,7 @@ public BeanMapperBuilder addConverter(BeanConverter converter) {
return this;
}

public BeanMapperBuilder addCollectionHandler(CollectionHandler handler) {
public BeanMapperBuilder addCollectionHandler(CollectionHandler<?> handler) {
this.customCollectionHandlers.add(handler);
return this;
}
Expand Down Expand Up @@ -114,7 +114,7 @@ public BeanMapperBuilder addAfterClearFlusher(AfterClearFlusher afterClearFlushe
return this;
}

public BeanMapperBuilder addLogicSecuredCheck(LogicSecuredCheck logicSecuredCheck) {
public BeanMapperBuilder addLogicSecuredCheck(LogicSecuredCheck<?, ?> logicSecuredCheck) {
this.configuration.addLogicSecuredCheck(logicSecuredCheck);
return this;
}
Expand Down Expand Up @@ -151,12 +151,12 @@ public BeanMapperBuilder downsizeTarget(List<String> includeFields) {
return this;
}

public BeanMapperBuilder setCollectionClass(Class collectionClass) {
public BeanMapperBuilder setCollectionClass(Class<?> collectionClass) {
this.configuration.setCollectionClass(collectionClass);
return this;
}

public BeanMapperBuilder setTargetClass(Class targetClass) {
public BeanMapperBuilder setTargetClass(Class<?> targetClass) {
this.configuration.setTargetClass(targetClass);
return this;
}
Expand Down Expand Up @@ -247,8 +247,8 @@ public BeanMapper build() {
return beanMapper;
}

private void addCollectionHandlers(List<CollectionHandler> collectionHandlers) {
for (CollectionHandler collectionHandler : collectionHandlers) {
private void addCollectionHandlers(List<CollectionHandler<?>> collectionHandlers) {
for (CollectionHandler<?> collectionHandler : collectionHandlers) {
attachCollectionHandler(collectionHandler);
}
}
Expand Down Expand Up @@ -277,7 +277,7 @@ private void addDefaultConverters() {
}
}

private void attachCollectionHandler(CollectionHandler collectionHandler) {
private void attachCollectionHandler(CollectionHandler<?> collectionHandler) {
configuration.addCollectionHandler(collectionHandler);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public abstract class AbstractCollectionHandler<C> implements CollectionHandler<
private final Class<C> type;
private final DefaultBeanInitializer beanInitializer = new DefaultBeanInitializer();

@SuppressWarnings("unchecked")
protected AbstractCollectionHandler() {
this.type = (Class<C>) Classes.getParameteredTypes(getClass())[0];
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public final <U, R> R convert(BeanMapper beanMapper, U source, Class<R> targetCl
this.beanMapper = beanMapper;
if (source == null) {
if (beanMapper != null)
beanMapper.getConfiguration().getDefaultValueForClass(targetClass);
beanMapper.configuration().getDefaultValueForClass(targetClass);
return null;
}
Check.argument(isMatchingSource(source.getClass()), "Unsupported source class.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ public synchronized void add(Class<?> source, Class<?> target, BeanConverter bea
var cachedConverters = beanConverterMap.get(source);

if (cachedConverters == null) {
beanConverterMap.put(source, new HashMap<>());
cachedConverters = beanConverterMap.get(target);
beanConverterMap.putIfAbsent(source, new HashMap<>());
cachedConverters = beanConverterMap.get(source);
cachedConverters.put(target, beanConverter);
}

cachedConverters.put(target, beanConverter);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package io.beanmapper.core.converter.collections;

public class AnnotationClass {
public record AnnotationClass(Class<?> annotationClass) {

public static final AnnotationClass EMPTY_ANNOTATION_CLASS = new AnnotationClass(null);

private final Class<?> annotationClass;

public AnnotationClass(Class<?> annotationClass) {
this.annotationClass = determineClass(annotationClass);
}
Expand All @@ -16,10 +14,6 @@ private Class<?> determineClass(Class<?> collectionElementType) {
collectionElementType;
}

public Class<?> getAnnotationClass() {
return this.annotationClass;
}

public boolean isEmpty() {
return this.annotationClass == null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public <R, U> U convert(
return BeanMapperPerformanceLogger.runTimed(() -> beanMapper.wrap()
.setCollectionClass(collectionHandler.getType())
.setCollectionUsage(beanPropertyMatch.getCollectionInstructions().getBeanCollectionUsage())
.setPreferredCollectionClass(beanPropertyMatch.getCollectionInstructions().getPreferredCollectionClass().getAnnotationClass())
.setPreferredCollectionClass(beanPropertyMatch.getCollectionInstructions().getPreferredCollectionClass().annotationClass())
.setFlushAfterClear(beanPropertyMatch.getCollectionInstructions().getFlushAfterClear())
.setTargetClass(beanPropertyMatch.getCollectionInstructions().getCollectionElementType().getType())
.setTarget(beanPropertyMatch.getTargetObject())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ public class CollectionElementType {
public static final CollectionElementType EMPTY_COLLECTION_ELEMENT_TYPE =
new CollectionElementType(null, true);

private final AnnotationClass collectionElementType;
private final AnnotationClass classOfCollectionElement;

private final boolean derived;

private CollectionElementType(Class<?> collectionElementType, boolean derived) {
this.collectionElementType = new AnnotationClass(collectionElementType);
private CollectionElementType(Class<?> classOfCollectionElement, boolean derived) {
this.classOfCollectionElement = new AnnotationClass(classOfCollectionElement);
this.derived = derived;
}

Expand All @@ -27,11 +27,11 @@ public boolean isDerived() {
}

public Class<?> getType() {
return collectionElementType.getAnnotationClass();
return classOfCollectionElement.annotationClass();
}

public boolean isEmpty() {
return collectionElementType.isEmpty();
return classOfCollectionElement.isEmpty();
}

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package io.beanmapper.core.converter.impl;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import io.beanmapper.BeanMapper;
import io.beanmapper.core.BeanPropertyMatch;
import io.beanmapper.core.converter.BeanConverter;
import io.beanmapper.utils.BeanMapperTraceLogger;
import io.beanmapper.utils.Classes;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
* This converter facilitates the conversion of an arbitrary amount of Optional wrappers, however, support for complex
* datastructures, such as Maps, Sets, List, etc. is limited to a single layer. As such, if the user requires support
Expand Down Expand Up @@ -79,8 +84,8 @@ private <S, T> Optional<T> convertToOptional(BeanMapper beanMapper, Optional<S>

S sourceObject = source.get();

if (genericType instanceof Class<?> targetType && Enum.class.isAssignableFrom((Class<?>) genericType) && sourceObject.getClass() == targetType) {
return (Optional<T>) Optional.ofNullable(sourceObject);
if (genericType instanceof Class<?> targetType && Enum.class.isAssignableFrom(targetType) && sourceObject.getClass() == targetType) {
return (Optional<T>) Optional.of(sourceObject);
}

// Place back in an Optional, as that is the target class
Expand All @@ -101,6 +106,6 @@ private Object convertToCollection(BeanMapper beanMapper, Object source, BeanPro
Type[] genericTypes = Classes.getParameteredTypes(beanPropertyMatch.getTarget().getClass(), beanPropertyMatch);
return new HashMap<>(beanMapper.map((Map<?, ?>) map, (Class<?>) genericTypes[1]));
}
return beanMapper.getConfiguration().getDefaultValueForClass(source.getClass());
return beanMapper.configuration().getDefaultValueForClass(source.getClass());
}
}
Loading