IDEA-166505 DOM: support more builtin converters

This commit is contained in:
Yann Cébron
2017-05-17 19:06:09 +02:00
parent b87c41269a
commit 051a31d28e
3 changed files with 105 additions and 23 deletions
@@ -19,9 +19,12 @@ import com.intellij.openapi.paths.PathReference;
import com.intellij.util.containers.ConcurrentInstanceMap;
import com.intellij.util.xml.*;
import com.intellij.util.xml.converters.PathReferenceConverter;
import com.intellij.util.xml.converters.values.NumberValueConverter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
@@ -43,10 +46,30 @@ class ConverterManagerImpl implements ConverterManager {
private final Map<Class,Converter> mySimpleConverters = new HashMap<>();
ConverterManagerImpl() {
mySimpleConverters.put(int.class, Converter.INTEGER_CONVERTER);
mySimpleConverters.put(Integer.class, Converter.INTEGER_CONVERTER);
mySimpleConverters.put(byte.class, new NumberValueConverter<>(byte.class, false));
mySimpleConverters.put(Byte.class, new NumberValueConverter<>(Byte.class, true));
mySimpleConverters.put(short.class, new NumberValueConverter<>(short.class, false));
mySimpleConverters.put(Short.class, new NumberValueConverter<>(Short.class, true));
mySimpleConverters.put(int.class, new NumberValueConverter<>(int.class, false));
mySimpleConverters.put(Integer.class, new NumberValueConverter<>(Integer.class, false));
mySimpleConverters.put(long.class, new NumberValueConverter<>(long.class, false));
mySimpleConverters.put(Long.class, new NumberValueConverter<>(Long.class, true));
mySimpleConverters.put(float.class, new NumberValueConverter<>(float.class, false));
mySimpleConverters.put(Float.class, new NumberValueConverter<>(Float.class, true));
mySimpleConverters.put(double.class, new NumberValueConverter<>(double.class, false));
mySimpleConverters.put(Double.class, new NumberValueConverter<>(Double.class, true));
mySimpleConverters.put(BigDecimal.class, new NumberValueConverter<>(BigDecimal.class, true));
mySimpleConverters.put(BigInteger.class, new NumberValueConverter<>(BigInteger.class, true));
mySimpleConverters.put(boolean.class, ResolvingConverter.BOOLEAN_CONVERTER);
mySimpleConverters.put(Boolean.class, ResolvingConverter.BOOLEAN_CONVERTER);
mySimpleConverters.put(String.class, Converter.EMPTY_CONVERTER);
mySimpleConverters.put(Object.class, Converter.EMPTY_CONVERTER);
mySimpleConverters.put(PathReference.class, PathReferenceConverter.INSTANCE);
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,46 +28,80 @@ import java.math.BigInteger;
import java.util.Collection;
import java.util.Collections;
public class NumberValueConverter extends ResolvingConverter<String> {
public class NumberValueConverter<T extends Number> extends ResolvingConverter<T> {
private final Class myNumberClass;
private final boolean myAllowEmpty;
public NumberValueConverter(@NotNull final Class numberClass, final boolean allowEmpty) {
public NumberValueConverter(@NotNull final Class<T> numberClass, final boolean allowEmpty) {
myNumberClass = numberClass;
myAllowEmpty = allowEmpty;
}
@Override
public String fromString(@Nullable @NonNls final String s, final ConvertContext context) {
public T fromString(@Nullable @NonNls final String s, final ConvertContext context) {
if (s == null) return null;
if (myAllowEmpty && s.trim().length() == 0) return s;
if (myAllowEmpty && s.trim().length() == 0) {
return null;
}
return parseNumber(s, myNumberClass) == null ? null : s;
//noinspection unchecked
return (T)parseNumber(s, myNumberClass);
}
@Override
public String toString(@Nullable final String s, final ConvertContext context) {
return null;
public String toString(@Nullable final T value, final ConvertContext context) {
return value == null ? null : parseText(value, myNumberClass);
}
@Override
public String getErrorMessage(@Nullable final String s, final ConvertContext context) {
if (s == null) return super.getErrorMessage(s, context);
return s.trim().length() == 0 ?
DomBundle.message("value.converter.format.exception.empty.string", myNumberClass.getName()) :
DomBundle.message("value.converter.format.exception", s, myNumberClass.getName());
final boolean isEmpty = s.trim().length() == 0;
if (isEmpty && myAllowEmpty) return null;
return isEmpty ?
DomBundle.message("value.converter.format.exception.empty.string", myNumberClass.getName()) :
DomBundle.message("value.converter.format.exception", s, myNumberClass.getName());
}
@NotNull
@Override
public Collection<? extends String> getVariants(ConvertContext context) {
public Collection<? extends T> getVariants(ConvertContext context) {
return Collections.emptySet();
}
@Nullable
public static String parseText(@NotNull Number value, @NotNull Class targetClass) {
if (targetClass.equals(Byte.class) || targetClass.equals(byte.class)) {
return Byte.toString((Byte)value);
}
if (targetClass.equals(Short.class) || targetClass.equals(short.class)) {
return Short.toString((Short)value);
}
if (targetClass.equals(Integer.class) || targetClass.equals(int.class)) {
return Integer.toString((Integer)value);
}
if (targetClass.equals(Long.class) || targetClass.equals(long.class)) {
return Long.toString((Long)value);
}
if (targetClass.equals(BigInteger.class)) {
return value.toString();
}
if (targetClass.equals(Float.class) || targetClass.equals(float.class)) {
return Float.toString((Float)value);
}
if (targetClass.equals(Double.class) || targetClass.equals(double.class)) {
return Double.toString((Double)value);
}
if (targetClass.equals(BigDecimal.class) || targetClass.equals(Number.class)) {
return ((BigDecimal)value).toPlainString();
}
return null;
}
@Nullable
public static Number parseNumber(@NotNull String text, @NotNull Class targetClass) {
try {
@@ -76,28 +110,29 @@ public class NumberValueConverter extends ResolvingConverter<String> {
if (targetClass.equals(Byte.class) || targetClass.equals(byte.class)) {
return Byte.decode(trimmed);
}
else if (targetClass.equals(Short.class) || targetClass.equals(short.class)) {
if (targetClass.equals(Short.class) || targetClass.equals(short.class)) {
return Short.decode(trimmed);
}
else if (targetClass.equals(Integer.class) || targetClass.equals(int.class)) {
if (targetClass.equals(Integer.class) || targetClass.equals(int.class)) {
return Integer.decode(trimmed);
}
else if (targetClass.equals(Long.class) || targetClass.equals(long.class)) {
if (targetClass.equals(Long.class) || targetClass.equals(long.class)) {
return Long.decode(trimmed);
}
else if (targetClass.equals(BigInteger.class)) {
if (targetClass.equals(BigInteger.class)) {
return decodeBigInteger(trimmed);
}
else if (targetClass.equals(Float.class) || targetClass.equals(float.class)) {
if (targetClass.equals(Float.class) || targetClass.equals(float.class)) {
return Float.valueOf(trimmed);
}
else if (targetClass.equals(Double.class) || targetClass.equals(double.class)) {
if (targetClass.equals(Double.class) || targetClass.equals(double.class)) {
return Double.valueOf(trimmed);
}
else if (targetClass.equals(BigDecimal.class) || targetClass.equals(Number.class)) {
if (targetClass.equals(BigDecimal.class) || targetClass.equals(Number.class)) {
return new BigDecimal(trimmed);
}
} catch (NumberFormatException ex) {
}
catch (NumberFormatException ex) {
return null;
}
return null;
@@ -28,6 +28,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -83,6 +84,15 @@ public class DomSimpleValuesTest extends DomTestCase {
assertEquals(true, createElement("<a>true</a>").getBoolean());
assertEquals("true", createElement("<a>true</a>").getBuffer().toString());
assertEquals((short)239, createElement("<a>239</a>").getShort());
assertEquals(new Long("239"), createElement("<a>239</a>").getLong());
assertEquals(new Float("239.42"), createElement("<a>239.42</a>").getFloat());
assertEquals(new BigDecimal("239.42"), createElement("<a>239.42</a>").getBigDecimal());
final MyElement bigDecimalValue = createElement("<a>239.42</a>");
bigDecimalValue.setValue(new BigDecimal("111.234"));
assertEquals("111.234", bigDecimalValue.getValue());
try {
createElement("<a>true</a>").getInt();
fail();
@@ -401,6 +411,20 @@ public class DomSimpleValuesTest extends DomTestCase {
@TagValue()
String getTagValue();
@TagValue
Long getLong();
@TagValue
Float getFloat();
@TagValue
short getShort();
@TagValue
BigDecimal getBigDecimal();
void setValue(BigDecimal value);
GenericDomValue<Integer> getGenericChild();
@SubTag("buffer")