Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.servicecomb.swagger.invocation.converter; 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.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.commons.lang3.reflect.TypeUtils; import org.apache.servicecomb.swagger.invocation.InvocationType; import org.apache.servicecomb.swagger.invocation.converter.impl.ConverterCommon; import org.apache.servicecomb.swagger.invocation.converter.impl.ConverterSame; import org.apache.servicecomb.swagger.invocation.converter.impl.SameElementArrayToList; import org.apache.servicecomb.swagger.invocation.converter.impl.SameElementArrayToSet; import org.apache.servicecomb.swagger.invocation.converter.impl.SameElementCollectionToArray; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class ConverterMgr { private static final Logger LOGGER = LoggerFactory.getLogger(ConverterMgr.class); // keysrc typekeytarget type private Map<Type, Map<Type, Converter>> srcTargetMap = new HashMap<>(); // keytarget type??jackson convert // ?????? // ???? private Map<Type, Converter> commonMap = new ConcurrentHashMap<>(); private Converter same = ConverterSame.getInstance(); private Converter arrayToList = SameElementArrayToList.getInstance(); private Converter arrayToSet = SameElementArrayToSet.getInstance(); // array??? private Map<Type, Converter> collectionToArrayMap = new ConcurrentHashMap<>(); @Autowired(required = false) public void setCustomizedConverters(List<CustomizedConverter> converters) { for (CustomizedConverter converter : converters) { Map<Type, Converter> map = srcTargetMap.computeIfAbsent(converter.getSrcType(), k -> new HashMap<>()); map.put(converter.getTargetType(), converter); } } public Converter findConverter(InvocationType invocationType, Type provider, Type swagger) { if (InvocationType.CONSUMER.equals(invocationType)) { return findConverter(provider, swagger); } return findConverter(swagger, provider); } public Converter findConverter(Type src, Type target) { Converter converter = findSrcTarget(src, target); if (converter != null) { return converter; } converter = findAssignable(src, target); if (converter != null) { return converter; } converter = findCollectionToArray(src, target); if (converter != null) { return converter; } converter = findArrayToCollection(src, target); if (converter != null) { return converter; } LOGGER.warn("Bad practice, low performance, convert from {} to {}", src, target); return findCommonConverter(target); } protected Converter findSrcTarget(Type src, Type target) { Map<Type, Converter> map = srcTargetMap.get(src); if (map == null) { return null; } return map.get(target); } protected Converter findCommonConverter(Type target) { Converter converter = commonMap.get(target); if (converter != null) { return converter; } // ??? converter = new ConverterCommon(target); commonMap.put(target, converter); return converter; } protected Converter findArrayToCollection(Type src, Type target) { if (src.getClass().equals(Class.class) && ParameterizedType.class.isAssignableFrom(target.getClass())) { Class<?> srcCls = (Class<?>) src; ParameterizedType targetType = (ParameterizedType) target; Class<?> targetCls = (Class<?>) targetType.getRawType(); if (srcCls.isArray() && srcCls.getComponentType().equals(targetType.getActualTypeArguments()[0])) { if (List.class.isAssignableFrom(targetCls)) { return arrayToList; } if (Set.class.isAssignableFrom(targetCls)) { return arrayToSet; } } } return null; } protected Converter findAssignable(Type src, Type target) { if (isAssignable(src, target)) { return same; } return null; } boolean isAssignable(Type src, Type target) { boolean assignable = TypeUtils.isAssignable(src, target); if (!assignable) { // void <--> java.lang.Void convert should be covered assignable = (src == void.class || src == Void.class) && (target == void.class || target == Void.class); } return assignable; } protected Converter findCollectionToArray(Type src, Type target) { if (ParameterizedType.class.isAssignableFrom(src.getClass()) && target.getClass().equals(Class.class)) { ParameterizedType srcType = (ParameterizedType) src; Class<?> srcCls = (Class<?>) srcType.getRawType(); Class<?> targetCls = (Class<?>) target; if (Collection.class.isAssignableFrom(srcCls) && targetCls.isArray() && srcType.getActualTypeArguments()[0].equals(targetCls.getComponentType())) { Converter converter = collectionToArrayMap.computeIfAbsent(target, k -> new SameElementCollectionToArray(targetCls.getComponentType())); return converter; } } return null; } }