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

org.gradle.internal.typeconversion.DefaultTypeConverter Maven / Gradle / Ivy

There is a newer version: 8.6
Show newest version
/*
 * Copyright 2015 the original author or authors.
 *
 * 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.gradle.internal.typeconversion;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.gradle.internal.Cast;
import org.gradle.internal.exceptions.DiagnosticsVisitor;
import org.gradle.internal.file.PathToFileResolver;

import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Map;

public class DefaultTypeConverter implements TypeConverter {
    private static final Map, Class> UNBOXED_TYPES = ImmutableMap., Class>builder()
        .put(Byte.class, byte.class)
        .put(Short.class, short.class)
        .put(Integer.class, int.class)
        .put(Boolean.class, boolean.class)
        .put(Float.class, float.class)
        .put(Character.class, char.class)
        .put(Double.class, double.class)
        .put(Long.class, long.class)
        .build();
    private final Map, NotationParser> parsers = Maps.newHashMap();

    private static  NotationParser build(NotationConverter converter, Class type) {
        return NotationParserBuilder
            .toType(type)
            .noImplicitConverters()
            .converter(converter)
            .toComposite();
    }

    private  void registerConverter(NotationConverter converter, Class type) {
        parsers.put(type, build(converter, type));
    }

    private  void registerStringConverter(NotationConverter converter, Class type) {
        parsers.put(type, build(new CharSequenceNotationConverter(converter), type));
    }

    private void registerConverters() {
        registerConverter(new DoubleNumberConverter(Double.class), Double.class);
        registerConverter(new DoubleNumberConverter(double.class), double.class);
        registerConverter(new FloatNumberConverter(Float.class), Float.class);
        registerConverter(new FloatNumberConverter(float.class), float.class);
        registerConverter(new IntegerNumberConverter(Integer.class), Integer.class);
        registerConverter(new IntegerNumberConverter(int.class), int.class);
        registerConverter(new LongNumberConverter(Long.class), Long.class);
        registerConverter(new LongNumberConverter(long.class), long.class);
        registerConverter(new ShortNumberConverter(Short.class), Short.class);
        registerConverter(new ShortNumberConverter(short.class), short.class);
        registerConverter(new ByteNumberConverter(Byte.class), Byte.class);
        registerConverter(new ByteNumberConverter(byte.class), byte.class);
        registerConverter(new BigDecimalNumberConverter(), BigDecimal.class);
        registerConverter(new BigIntegerNumberConverter(), BigInteger.class);

        CharSequenceConverter booleanConverter = new BooleanConverter();
        registerStringConverter(booleanConverter, Boolean.class);
        registerStringConverter(booleanConverter, boolean.class);

        registerStringConverter(new CharacterConverter(Character.class, Character.class), Character.class);
        registerStringConverter(new CharacterConverter(Character.class, char.class), char.class);

        registerConverter(new StringConverter(), String.class);
    }

    private abstract static class CharSequenceConverter implements NotationConverter {
        final Class type;

        public CharSequenceConverter(Class type) {
            this.type = type;
        }

        public void describe(DiagnosticsVisitor visitor) {
            visitor.candidate("A String or CharSequence");
            visitor.candidate("A " + type.getSimpleName());
        }
    }

    private static class StringConverter implements NotationConverter {
        @Override
        public void convert(Object notation, NotationConvertResult result) throws TypeConversionException {
            if (notation instanceof CharSequence || notation instanceof Number || notation instanceof Boolean || notation instanceof Character || notation instanceof File) {
                result.converted(notation.toString());
            }
        }

        @Override
        public void describe(DiagnosticsVisitor visitor) {
            visitor.candidate("A String or CharSequence or Character");
            visitor.candidate("Any Number");
            visitor.candidate("A Boolean");
            visitor.candidate("A File");
        }
    }

    private abstract static class NumberConverter implements NotationConverter {
        private final Class type;

        protected NumberConverter(Class type) {
            this.type = type;
        }

        @Override
        public void describe(DiagnosticsVisitor visitor) {
            visitor.candidate("A String or CharSequence");
            visitor.candidate("Any Number");
        }

        public void convert(Object notation, NotationConvertResult result) throws TypeConversionException {
            if (notation instanceof CharSequence) {
                try {
                    convertNumberToNumber(new BigDecimal(notation.toString().trim()), result);
                } catch (ArithmeticException e) {
                    throw new TypeConversionException(String.format("Cannot convert value '%s' to type %s",
                        notation, type.getSimpleName()), e);
                } catch (NumberFormatException e) {
                    throw new TypeConversionException(String.format("Cannot convert value '%s' to type %s",
                        notation, type.getSimpleName()), e);
                }
            } else if (notation instanceof Number) {
                try {
                    convertNumberToNumber(toBigDecimal((Number) notation), result);
                } catch (ArithmeticException e) {
                    throw new TypeConversionException(String.format("Cannot convert value '%s' to type %s",
                        notation, type.getSimpleName()), e);
                }
            }
        }

        private static BigDecimal toBigDecimal(Number notation) {
            if (notation instanceof BigDecimal) {
                return (BigDecimal) notation;
            }
            if (notation instanceof BigInteger) {
                return new BigDecimal((BigInteger) notation);
            }
            if (notation instanceof Float) {
                return new BigDecimal(notation.floatValue());
            }
            if (notation instanceof Double) {
                return new BigDecimal(notation.doubleValue());
            }
            return new BigDecimal(notation.longValue());
        }

        protected abstract void convertNumberToNumber(BigDecimal n, NotationConvertResult result);
    }

    public DefaultTypeConverter(final PathToFileResolver fileResolver) {
        registerConverter(new CharSequenceNotationConverter(new CharSequenceConverter(File.class) {
            public void convert(String notation, NotationConvertResult result) throws TypeConversionException {
                result.converted(fileResolver.resolve(notation));
            }
        }), File.class);
        registerConverters();
    }

    public Object convert(Object notation, Class type, boolean primitive) throws TypeConversionException {
        if (type.isInstance(notation)) {
            return notation;
        }
        if (!primitive && notation == null) {
            return null;
        }

        if (type.isEnum()) {
            Class enumType = Cast.uncheckedCast(type);
            return convertEnum(enumType, notation);
        }

        NotationParser parser;
        parser = parsers.get(primitive ? UNBOXED_TYPES.get(type) : type);
        if (parser == null) {
            throw new IllegalArgumentException("Don't know how to convert to type " + type.getName());
        }

        return parser.parseNotation(notation);
    }

    private > T convertEnum(Class type, Object notation) {
        return NotationParserBuilder
                .toType(type)
                .noImplicitConverters()
                .fromCharSequence(new EnumFromCharSequenceNotationParser(type))
                .toComposite()
                .parseNotation(notation);
    }

    private static class DoubleNumberConverter extends NumberConverter {
        public DoubleNumberConverter(Class cl) {
            super(cl);
        }

        @Override
        protected void convertNumberToNumber(BigDecimal n, NotationConvertResult result) {
            result.converted(n.doubleValue());
        }
    }

    private static class FloatNumberConverter extends NumberConverter {
        public FloatNumberConverter(Class cl) {
            super(cl);
        }

        @Override
        protected void convertNumberToNumber(BigDecimal n, NotationConvertResult result) {
            result.converted(n.floatValue());
        }
    }

    private static class IntegerNumberConverter extends NumberConverter {
        public IntegerNumberConverter(Class cl) {
            super(cl);
        }

        @Override
        protected void convertNumberToNumber(BigDecimal n, NotationConvertResult result) {
            result.converted(n.intValueExact());
        }
    }

    private static class LongNumberConverter extends NumberConverter {
        public LongNumberConverter(Class cl) {
            super(cl);
        }

        @Override
        protected void convertNumberToNumber(BigDecimal n, NotationConvertResult result) {
            result.converted(n.longValueExact());
        }
    }

    private static class ShortNumberConverter extends NumberConverter {
        public ShortNumberConverter(Class cl) {
            super(cl);
        }

        @Override
        protected void convertNumberToNumber(BigDecimal n, NotationConvertResult result) {
            result.converted(n.shortValueExact());
        }
    }

    private static class ByteNumberConverter extends NumberConverter {
        public ByteNumberConverter(Class cl) {
            super(cl);
        }

        @Override
        protected void convertNumberToNumber(BigDecimal n, NotationConvertResult result) {
            result.converted(n.byteValueExact());
        }
    }

    private static class BigDecimalNumberConverter extends NumberConverter {
        public BigDecimalNumberConverter() {
            super(BigDecimal.class);
        }

        @Override
        protected void convertNumberToNumber(BigDecimal n, NotationConvertResult result) {
            result.converted(n);
        }
    }

    private static class BigIntegerNumberConverter extends NumberConverter {
        public BigIntegerNumberConverter() {
            super(BigInteger.class);
        }

        @Override
        protected void convertNumberToNumber(BigDecimal n, NotationConvertResult result) {
            result.converted(n.toBigIntegerExact());
        }
    }

    private static class BooleanConverter extends CharSequenceConverter {
        public BooleanConverter() {
            super(Boolean.class);
        }

        public void convert(String notation, NotationConvertResult result) throws TypeConversionException {
            result.converted("true".equals(notation));
        }
    }

    private class CharacterConverter extends CharSequenceConverter {
        private final Class target;

        public CharacterConverter(Class boxed, Class target) {
            super(boxed);
            this.target = target;
        }

        public void convert(String notation, NotationConvertResult result) throws TypeConversionException {
            if (notation.length() != 1) {
                throw new TypeConversionException(String.format("Cannot convert string value '%s' with length %d to type %s",
                        notation, notation.length(), target.getSimpleName()));
            }

            result.converted(notation.charAt(0));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy