1 /*
2  * Copyright 2011 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.modelmapper.internal.converter;
17
18 import java.lang.reflect.Array;
19 import java.lang.reflect.GenericArrayType;
20 import java.util.Collection;
21
22 import java.util.Iterator;
23 import org.modelmapper.internal.util.Iterables;
24 import org.modelmapper.internal.util.Types;
25 import org.modelmapper.spi.ConditionalConverter;
26 import org.modelmapper.spi.MappingContext;
27
28 /**
29  * Converts {@link Collection} and array instances to array instances.
30  * 
31  * @author Jonathan Halterman
32  */

33 class ArrayConverter implements ConditionalConverter<Object, Object> {
34   @Override
35   public MatchResult match(Class<?> sourceType, Class<?> destinationType) {
36     return Iterables.isIterable(sourceType) && destinationType.isArray() ? MatchResult.FULL
37         : MatchResult.NONE;
38   }
39
40   @Override
41   public Object convert(MappingContext<Object, Object> context) {
42     Object source = context.getSource();
43     if (source == null)
44       return null;
45
46     boolean destinationProvided = context.getDestination() != null;
47     Object destination = createDestination(context);
48
49     Class<?> elementType = getElementType(context);
50     int index = 0;
51     for (Iterator<Object> iterator = Iterables.iterator(source); iterator.hasNext(); index++) {
52       Object sourceElement = iterator.next();
53       Object element = null;
54       if (destinationProvided)
55         element = Iterables.getElement(destination, index);
56       if (sourceElement != null) {
57         MappingContext<?, ?> elementContext = element == null
58             ? context.create(sourceElement, elementType)
59             : context.create(sourceElement, element);
60         element = context.getMappingEngine().map(elementContext);
61       }
62       Array.set(destination, index, element);
63     }
64
65     return destination;
66   }
67
68   @SuppressWarnings("all")
69   private Object createDestination(MappingContext<Object, Object> context) {
70     int sourceLength = Iterables.getLength(context.getSource());
71     int destinationLength = context.getDestination() != null ? Iterables.getLength(context.getDestination()) : 0;
72     int newLength = Math.max(sourceLength, destinationLength);
73     Object originalDestination = context.getDestination();
74
75     Class<?> destType = context.getDestinationType();
76     Object destination = Array.newInstance(destType.isArray() ? destType.getComponentType() : destType, newLength);
77     if (originalDestination != null)
78       System.arraycopy(originalDestination, 0, destination, 0, destinationLength);
79     return destination;
80   }
81
82   private Class<?> getElementType(MappingContext<Object, Object> context) {
83     if (context.getGenericDestinationType() instanceof GenericArrayType)
84       return Types.rawTypeFor(context.getGenericDestinationType())
85           .getComponentType();
86     return context.getDestinationType().getComponentType();
87   }
88 }
89