11package io .beanmapper .strategy ;
22
3+ import io .beanmapper .BeanMapper ;
4+ import io .beanmapper .annotations .BeanAlias ;
5+ import io .beanmapper .annotations .BeanRecordConstruct ;
6+ import io .beanmapper .annotations .BeanRecordConstructMode ;
7+ import io .beanmapper .config .Configuration ;
8+ import io .beanmapper .core .converter .BeanConverter ;
9+ import io .beanmapper .core .inspector .PropertyAccessor ;
10+ import io .beanmapper .core .inspector .PropertyAccessors ;
11+ import io .beanmapper .exceptions .BeanInstantiationException ;
12+ import io .beanmapper .exceptions .RecordConstructorConflictException ;
13+ import io .beanmapper .exceptions .RecordNoAvailableConstructorsExceptions ;
14+ import io .beanmapper .utils .BeanMapperTraceLogger ;
15+ import io .beanmapper .utils .Records ;
16+
317import java .lang .reflect .Constructor ;
418import java .lang .reflect .Field ;
519import java .lang .reflect .InvocationTargetException ;
1630import java .util .stream .Collectors ;
1731import java .util .stream .Stream ;
1832
19- import io .beanmapper .BeanMapper ;
20- import io .beanmapper .annotations .BeanAlias ;
21- import io .beanmapper .annotations .BeanRecordConstruct ;
22- import io .beanmapper .annotations .BeanRecordConstructMode ;
23- import io .beanmapper .config .Configuration ;
24- import io .beanmapper .core .converter .BeanConverter ;
25- import io .beanmapper .exceptions .BeanInstantiationException ;
26- import io .beanmapper .exceptions .RecordConstructorConflictException ;
27- import io .beanmapper .exceptions .RecordNoAvailableConstructorsExceptions ;
28- import io .beanmapper .exceptions .SourceFieldAccessException ;
29- import io .beanmapper .utils .BeanMapperTraceLogger ;
30- import io .beanmapper .utils .Records ;
31-
3233/**
3334 * MapToRecordStrategy offers a comprehensive implementation of the MapToClassStrategy, targeted towards mapping a class
3435 * to a record.
@@ -49,8 +50,9 @@ public <S, T> T map(final S source) {
4950
5051 Class <T > targetClass = this .getConfiguration ().getTargetClass ();
5152
52- if (source .getClass (). equals ( targetClass ))
53+ if (source .getClass () == targetClass ) {
5354 return targetClass .cast (source );
55+ }
5456
5557 // We use the RecordToAny-converter in case the source is also a Record. Furthermore, allowing the use of custom
5658 // converters increases flexibility of the library.
@@ -64,9 +66,12 @@ public <S, T> T map(final S source) {
6466 }
6567
6668 Map <String , Field > sourceFields = getSourceFields (source );
69+ Map <String , PropertyAccessor > sourcePropertyAccessors = sourceFields .entrySet ().stream ()
70+ .map (entry -> Map .entry (entry .getKey (), PropertyAccessors .findProperty (source .getClass (), entry .getValue ().getName ())))
71+ .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue ));
6772 Constructor <T > constructor = (Constructor <T >) getSuitableConstructor (sourceFields , targetClass );
6873 String [] fieldNamesForConstructor = getNamesOfConstructorParameters (targetClass , constructor );
69- List <Object > values = getValuesOfFields (source , sourceFields , sourceFields , Arrays .stream (fieldNamesForConstructor ));
74+ List <Object > values = getValuesOfFields (source , sourcePropertyAccessors , Arrays .stream (fieldNamesForConstructor ));
7075
7176 return targetClass .cast (constructTargetObject (constructor , values ));
7277 }
@@ -76,8 +81,8 @@ public <S, T> T map(final S source) {
7681 * present.
7782 *
7883 * @param sourceClass The class of the source-object.
84+ * @param <S> The type of the sourceClass.
7985 * @return A Map containing the fields of the source-class, mapped by the name of the field, or the value of an available BeanAlias.
80- * @param <S> The type of the sourceClass.
8186 */
8287 private <S > Map <String , Field > getFieldsOfClass (final Class <S > sourceClass ) {
8388 return Arrays .stream (sourceClass .getDeclaredFields ())
@@ -156,15 +161,10 @@ private <T> String[] getNamesOfConstructorParameters(final Class<T> targetClass,
156161 return getNamesOfRecordComponents (targetClass );
157162 }
158163
159- private <S > List <Object > getValuesOfFields (final S source , final Map <String , Field > sourceFields , final Map <String , Field > fieldMap ,
160- final Stream <String > fieldNamesForConstructor ) {
161- return fieldNamesForConstructor .map (fieldName -> {
162- Field field = fieldMap .get (fieldName );
163- if (field != null ) {
164- return field ;
165- }
166- return sourceFields .get (fieldName );
167- }).map (field -> getValueFromField (source , field ))
164+ private <S > List <Object > getValuesOfFields (final S source , final Map <String , PropertyAccessor > accessors ,
165+ final Stream <String > fieldNamesForConstructor ) {
166+ return fieldNamesForConstructor .map (accessors ::get )
167+ .map (accessor -> getValueFromField (source , accessor ))
168168 .toList ();
169169 }
170170
@@ -196,17 +196,11 @@ private <T> T constructTargetObject(final Constructor<T> targetConstructor, fina
196196 }
197197 }
198198
199- private <S > Object getValueFromField (final S source , final Field field ) {
200- if (field == null ) {
199+ private <S > Object getValueFromField (final S source , PropertyAccessor accessor ) {
200+ if (accessor == null || ! accessor . isReadable () ) {
201201 return null ;
202202 }
203- try {
204- if (!field .canAccess (source ))
205- field .setAccessible (true );
206- return field .get (source );
207- } catch (IllegalAccessException ex ) {
208- throw new SourceFieldAccessException (this .getConfiguration ().getTargetClass (), source .getClass (), "Could not access field " + field .getName (), ex );
209- }
203+ return accessor .getValue (source );
210204 }
211205
212206 private <T > Constructor <?> getSuitableConstructor (final Map <String , Field > sourceFields , final Class <T > targetClass ) {
@@ -239,7 +233,7 @@ private <T> Constructor<?> getSuitableConstructor(final Map<String, Field> sourc
239233 }
240234
241235 private <T > Optional <Constructor <T >> getConstructorWithMostMatchingParameters (final List <Constructor <T >> constructors ,
242- final Map <String , Field > sourceFields ) {
236+ final Map <String , Field > sourceFields ) {
243237 for (var constructor : constructors ) {
244238 BeanRecordConstruct recordConstruct = constructor .getAnnotation (BeanRecordConstruct .class );
245239 List <Field > relevantFields = Arrays .stream (recordConstruct .value ())
0 commit comments