All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.microbean.microprofile.config.Converters Maven / Gradle / Ivy

The newest version!
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
 *
 * Copyright © 2018–2019 microBean™.
 *
 * Licensed 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.microbean.microprofile.config;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import javax.annotation.Priority;

import org.eclipse.microprofile.config.spi.Converter;

final class Converters {

  private Converters() {
    super();
  }

  static final Type getConversionType(final Converter converter) {
    final Type returnValue;
    if (converter instanceof PrioritizedConverter) {
      returnValue = ((PrioritizedConverter)converter).getConversionType();
    } else {
      returnValue = getConversionType(Objects.requireNonNull(converter).getClass());
    }
    return returnValue;
  }

  static final int getPriority(final Converter converter) {
    int returnValue = 100; // per specification by default
    if (converter != null) {
      if (converter instanceof PrioritizedConverter) {
        returnValue = ((PrioritizedConverter)converter).getPriority();
      } else {
        final Integer priorityInteger = getPriority(converter.getClass());
        if (priorityInteger != null) {
          returnValue = priorityInteger.intValue();
        }
      }
    }
    return returnValue;
  }

  private static final Integer getPriority(final AnnotatedElement annotatedElement) {
    Integer returnValue = null;
    if (annotatedElement != null) {
      final Priority priority = annotatedElement.getAnnotation(Priority.class);
      if (priority != null) {
        returnValue = Integer.valueOf(priority.value());
      }
    }
    return returnValue;
  }

  static final Type getConversionType(final Type type) {
    return getConversionType(type, null, null);
  }

  private static final Type getConversionType(final Type type, Set seen, Map, Type> reifiedTypes) {
    Type returnValue = null;
    if (type != null) {
      if (seen == null) {
        seen = new HashSet<>();
      }
      if (reifiedTypes == null) {
        reifiedTypes = new HashMap<>();
      }
      if (!seen.contains(type)) {
        seen.add(type);

        if (type instanceof Class) {
          final Class c = (Class)type;
          if (Converter.class.isAssignableFrom(c)) {
            final Type[] genericInterfaces = c.getGenericInterfaces();
            assert genericInterfaces != null;
            for (final Type genericInterface : genericInterfaces) {
              returnValue = getConversionType(genericInterface, seen, reifiedTypes); // XXX recursive call
              if (returnValue != null) {
                break;
              }
            }
            if (returnValue == null) {
              returnValue = getConversionType(c.getSuperclass(), seen, reifiedTypes); // XXX recursive call
            }
          }

        } else if (type instanceof ParameterizedType) {
          final ParameterizedType pt = (ParameterizedType)type;
          final Type rawType = pt.getRawType();
          assert rawType instanceof GenericDeclaration;
          final TypeVariable[] typeParameters = ((GenericDeclaration)rawType).getTypeParameters();
          assert typeParameters != null;
          final Type[] actualTypeArguments = pt.getActualTypeArguments();
          assert actualTypeArguments != null;
          assert actualTypeArguments.length == typeParameters.length;
          if (actualTypeArguments.length > 0) {
            for (int i = 0; i < actualTypeArguments.length; i++) {
              Type actualTypeArgument = actualTypeArguments[i];
              if (actualTypeArgument instanceof Class ||
                  actualTypeArgument instanceof ParameterizedType) {
                reifiedTypes.put(typeParameters[i], actualTypeArgument);
              } else if (actualTypeArgument instanceof TypeVariable) {
                final Type reifiedType = reifiedTypes.get((TypeVariable)actualTypeArgument);
                if (reifiedType == null) {
                  reifiedTypes.put((TypeVariable)actualTypeArgument, Object.class);
                  actualTypeArgument = Object.class;
                } else {
                  actualTypeArgument = reifiedType;
                }
                assert actualTypeArgument != null;
                assert (actualTypeArgument instanceof ParameterizedType || actualTypeArgument instanceof Class) : "Unexpected actualTypeArgument: " + actualTypeArgument;
                reifiedTypes.put(typeParameters[i], actualTypeArgument);
              }
            }
          }
          if (Converter.class.equals(rawType)) {
            assert actualTypeArguments.length == 1;
            final Type typeArgument = actualTypeArguments[0];
            if (typeArgument instanceof Class ||
                typeArgument instanceof ParameterizedType) {
              returnValue = typeArgument;
            } else if (typeArgument instanceof TypeVariable) {
              final TypeVariable typeVariable = (TypeVariable)typeArgument;
              returnValue = reifiedTypes.get(typeVariable);
              assert returnValue instanceof ParameterizedType || returnValue instanceof Class : "Unexpected returnValue: " + returnValue;
            } else {
              throw new IllegalArgumentException("Unhandled conversion type: " + typeArgument);
            }
          } else {
            returnValue = getConversionType(rawType, seen, reifiedTypes); // XXX recursive call
          }

        } else {
          throw new IllegalArgumentException("Unhandled type: " + type);
        }

      }
    }
    return returnValue;
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy