1 /*
2  * Copyright 2018 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;
17
18 import java.util.AbstractList;
19 import java.util.Collection;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Map;
23 import net.jodah.typetools.TypeResolver;
24 import org.modelmapper.internal.util.Assert;
25 import org.modelmapper.internal.util.CopyOnWriteLinkedHashMap;
26
27 /**
28  * CopyOnWriteArrayList that resolves based on given types.
29  *
30  * @author Chun Han Hsiao
31  */

32 public class TypeResolvingList<T> extends AbstractList<T> {
33   private final Map<T, Class<?>> elements = new CopyOnWriteLinkedHashMap<T, Class<?>>();
34   private final Class<? super T> valueAccessorType;
35
36   public TypeResolvingList(Class<? super T> valueAccessorType) {
37     this.valueAccessorType = valueAccessorType;
38   }
39
40   @Override
41   public void add(int index, T element) {
42     addElement(element);
43   }
44
45   @Override
46   public int size() {
47     return elements.size();
48   }
49
50   @Override
51   public boolean add(T element) {
52     return addElement(element);
53   }
54
55   @Override
56   public T get(int index) {
57     Iterator<T> iterator = elements.keySet().iterator();
58     for (int i = 0; i < index; i++) {
59       iterator.next();
60     }
61     return iterator.next();
62   }
63
64   @Override
65   public boolean addAll(Collection<? extends T> c) {
66     boolean changed = false;
67     for (T e : c) {
68       changed = addElement(e) || changed;
69     }
70
71     return changed;
72   }
73
74   @Override
75   public boolean addAll(int index, Collection<? extends T> c) {
76     throw new UnsupportedOperationException();
77   }
78
79   @Override
80   public void clear() {
81     elements.clear();
82   }
83
84   @Override
85   public T remove(int index) {
86     T element = get(index);
87     elements.remove(element);
88     return element;
89   }
90
91   @Override
92   public boolean remove(Object o) {
93     elements.remove(o);
94     return true;
95   }
96
97   @Override
98   public boolean removeAll(Collection<?> c) {
99     for (Object e : c) {
100       @SuppressWarnings("unchecked")
101       T t = (T) e;
102       elements.remove(t);
103     }
104     return true;
105   }
106
107   @Override
108   public boolean retainAll(Collection<?> c) {
109     throw new UnsupportedOperationException();
110   }
111
112   @Override
113   public T set(int index, T element) {
114     throw new UnsupportedOperationException();
115   }
116
117   @Override
118   public List<T> subList(int fromIndex, int toIndex) {
119     throw new UnsupportedOperationException();
120   }
121
122   private boolean addElement(T element) {
123     Assert.notNull(element, "element");
124     Class<?> typeArgument = TypeResolver.resolveRawArgument(valueAccessorType, element.getClass());
125     if (typeArgument == null) {
126       throw new IllegalArgumentException("Must declare source type argument <T> for the " + valueAccessorType.getSimpleName());
127     }
128     elements.put(element, typeArgument);
129     return true;
130   }
131
132   public T first(Class<?> type) {
133     for (Map.Entry<T, Class<?>> entry : elements.entrySet())
134       if (entry.getValue().isAssignableFrom(type))
135         return entry.getKey();
136     return null;
137   }
138 }
139