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

io.smallrye.config.ImplicitConverters Maven / Gradle / Ivy

/*
 * Copyright 2017 Red Hat, Inc.
 *
 * 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 io.smallrye.config;

import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

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

/**
 * Based on GERONIMO-6595 support implicit converters.
 *
 * @author Jeff Mesnil (c) 2017 Red Hat inc.
 */
class ImplicitConverters {

    private ImplicitConverters() {
    }

    static  Converter getConverter(Class clazz) {
        // implicit converters required by the specification
        Converter converter = getConverterFromStaticMethod(clazz, "of", String.class);
        if (converter == null) {
            converter = getConverterFromStaticMethod(clazz, "of", CharSequence.class);
            if (converter == null) {
                converter = getConverterFromStaticMethod(clazz, "valueOf", String.class);
                if (converter == null) {
                    converter = getConverterFromStaticMethod(clazz, "valueOf", CharSequence.class);
                    if (converter == null) {
                        converter = getConverterFromStaticMethod(clazz, "parse", String.class);
                        if (converter == null) {
                            converter = getConverterFromStaticMethod(clazz, "parse", CharSequence.class);
                            if (converter == null) {
                                converter = getConverterFromConstructor(clazz, String.class);
                                if (converter == null) {
                                    converter = getConverterFromConstructor(clazz, CharSequence.class);
                                }
                            }
                        }
                    }
                }
            }
        }
        return converter;
    }

    private static  Converter getConverterFromConstructor(Class clazz, Class paramType) {
        try {
            final Constructor declaredConstructor = SecuritySupport.getDeclaredConstructor(clazz, paramType);
            if (!isAccessible(declaredConstructor)) {
                SecuritySupport.setAccessible(declaredConstructor, true);
            }
            return new ConstructorConverter<>(declaredConstructor);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    private static  Converter getConverterFromStaticMethod(Class clazz, String methodName,
            Class paramType) {
        try {
            final Method method = clazz.getMethod(methodName, paramType);
            if (clazz != method.getReturnType()) {
                // doesn't meet requirements of the spec
                return null;
            }
            if (!Modifier.isStatic(method.getModifiers())) {
                return null;
            }
            if (!isAccessible(method)) {
                SecuritySupport.setAccessible(method, true);
            }
            return new StaticMethodConverter<>(clazz, method);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

    private static boolean isAccessible(Executable e) {
        return Modifier.isPublic(e.getModifiers()) && Modifier.isPublic(e.getDeclaringClass().getModifiers()) ||
                e.isAccessible();
    }

    static class StaticMethodConverter implements Converter, Serializable {

        private static final long serialVersionUID = 3350265927359848883L;

        private final Class clazz;
        private final Method method;

        StaticMethodConverter(Class clazz, Method method) {
            assert clazz == method.getReturnType();
            this.clazz = clazz;
            this.method = method;
        }

        @Override
        public T convert(String value) {
            if (value.isEmpty()) {
                return null;
            }
            try {
                return clazz.cast(method.invoke(null, value));
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw ConfigMessages.msg.staticMethodConverterFailure(e);
            }
        }

        Object writeReplace() {
            return new Serialized(method.getDeclaringClass(), method.getName(), method.getParameterTypes()[0]);
        }

        static final class Serialized implements Serializable {
            private static final long serialVersionUID = -6334004040897615452L;

            private final Class c;
            @SuppressWarnings("unused")
            private final String m;
            @SuppressWarnings("unused")
            private final Class p;

            Serialized(final Class c, final String m, final Class p) {
                this.c = c;
                this.m = m;
                this.p = p;
            }

            Object readResolve() throws ObjectStreamException {
                return getConverter(c);
            }
        }
    }

    static class ConstructorConverter implements Converter, Serializable {

        private static final long serialVersionUID = 3350265927359848883L;

        private final Constructor ctor;

        public ConstructorConverter(final Constructor ctor) {
            this.ctor = ctor;
        }

        @Override
        public T convert(String value) {
            if (value.isEmpty()) {
                return null;
            }
            try {
                return ctor.newInstance(value);
            } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
                throw ConfigMessages.msg.constructorConverterFailure(e);
            }
        }

        Object writeReplace() {
            return new Serialized(ctor.getDeclaringClass(), ctor.getParameterTypes()[0]);
        }

        static final class Serialized implements Serializable {
            private static final long serialVersionUID = -2903564775826815453L;

            private final Class c;
            @SuppressWarnings("unused")
            private final Class p;

            Serialized(final Class c, final Class p) {
                this.c = c;
                this.p = p;
            }

            Object readResolve() throws ObjectStreamException {
                return getConverter(c);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy