1 /*
2  * Copyright 2022 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 net.jodah.typetools.TypeResolver;
19 import org.modelmapper.internal.util.Types;
20 import org.modelmapper.spi.*;
21
22 import java.lang.reflect.ParameterizedType;
23 import java.util.Optional;
24
25 /**
26  * Converts  {@link Optional} to {@link Optional}
27  */

28 class OptionalConverter implements ConditionalConverter<Optional<?>, Optional<?>> {
29   @Override
30   public MatchResult match(Class<?> sourceType, Class<?> destinationType) {
31     return (Optional.class.equals(sourceType) && Optional.class.equals(destinationType))
32         ? MatchResult.FULL
33         : MatchResult.NONE;
34   }
35
36   @Override
37   @SuppressWarnings("all")
38   public Optional<?> convert(MappingContext<Optional<?>, Optional<?>> mappingContext) {
39     Class<?> optionalType = getElementType(mappingContext);
40     Optional<?> source = mappingContext.getSource();
41     if (source == null) {
42       return null;
43     } else if (source.isPresent()) {
44       MappingContext<?, ?> optionalContext = mappingContext.create(source.get(), optionalType);
45       return Optional.ofNullable(mappingContext.getMappingEngine().map(optionalContext));
46     } else {
47       return Optional.empty();
48     }
49   }
50
51
52   private Class<?> getElementType(MappingContext<Optional<?>, Optional<?>> mappingContext) {
53     Mapping mapping = mappingContext.getMapping();
54     if (mapping instanceof PropertyMapping) {
55       PropertyInfo destInfo = mapping.getLastDestinationProperty();
56       Class<?> elementType = TypeResolver.resolveRawArgument(destInfo.getGenericType(),
57           destInfo.getInitialType());
58       return elementType == TypeResolver.Unknown.class ? Object.class : elementType;
59     } else if (mappingContext.getGenericDestinationType() instanceof ParameterizedType) {
60       return Types.rawTypeFor(((ParameterizedType) mappingContext.getGenericDestinationType()).getActualTypeArguments()[0]);
61     }
62
63     return Object.class;
64   }
65
66 }
67