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

io.inverno.mod.configuration.internal.JavaStringConverter Maven / Gradle / Ivy

There is a newer version: 1.11.0
Show newest version
/*
 * Copyright 2021 Jeremy KUHN
 *
 * 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.inverno.mod.configuration.internal;

import io.inverno.mod.base.converter.ConverterException;
import io.inverno.mod.base.converter.ObjectConverter;
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Currency;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;
import org.apache.commons.text.StringEscapeUtils;

/**
 * 

* Java String {@link ObjectConverter} implementation that converts primitive and common types from/to Java String literals (ie. escaping characters in a String using Java String rules). *

* * @author Jeremy Kuhn * @since 1.0 * * @see ObjectConverter */ public class JavaStringConverter implements ObjectConverter { /** * Default array list separator */ public static final String DEFAULT_ARRAY_LIST_SEPARATOR = ","; private String arrayListSeparator; /** *

* Creates a Java String converter with the default array/list separator. *

*/ public JavaStringConverter() { this(DEFAULT_ARRAY_LIST_SEPARATOR); } /** *

* Creates a Java String converter with the specified array/list separator. *

* * @param arrayListSeparator an array/list separator */ public JavaStringConverter(String arrayListSeparator) { this.arrayListSeparator = arrayListSeparator; } /** *

* Returns the array/list separator used to convert lists and arrays. *

* * @return an array/list separator */ public String getArrayListSeparator() { return arrayListSeparator; } /** *

* Sets the array/list separator used to convert lists and arrays. *

* * @param arrayListSeparator an array/list separator */ public void setArrayListSeparator(String arrayListSeparator) { this.arrayListSeparator = arrayListSeparator; } @Override public String encode(T value) { return this.encode(value, value.getClass()); } @Override public String encode(T value, Class type) throws ConverterException { if(value == null) { return null; } if(type.isArray()) { return this.encodeArray((Object[])value, type.getComponentType()); } if(Collection.class.isAssignableFrom(type)) { return this.encodeCollection((Collection)value); } if(Byte.class.equals(type)) { return this.encode((Byte)value); } if(Short.class.equals(type)) { return this.encode((Short)value); } if(Integer.class.equals(type)) { return this.encode((Integer)value); } if(Long.class.equals(type)) { return this.encode((Long)value); } if(Float.class.equals(type)) { return this.encode((Float)value); } if(Double.class.equals(type)) { return this.encode((Double)value); } if(Character.class.equals(type)) { return this.encode((Character)value); } if(Boolean.class.equals(type)) { return this.encode((Boolean)value); } if(String.class.equals(type)) { return this.encode((String)value); } if(BigInteger.class.isAssignableFrom(type)) { return this.encode((BigInteger)value); } if(BigDecimal.class.isAssignableFrom(type)) { return this.encode((BigDecimal)value); } if(LocalDate.class.equals(type)) { return this.encode((LocalDate)value); } if(LocalDateTime.class.equals(type)) { return this.encode((LocalDateTime)value); } if(ZonedDateTime.class.equals(type)) { return this.encode((ZonedDateTime)value); } if(Currency.class.equals(type)) { return this.encode((Currency)value); } if(Locale.class.equals(type)) { return this.encode((Locale)value); } if(File.class.isAssignableFrom(type)) { return this.encode((File)value); } if(Path.class.isAssignableFrom(type)) { return this.encode((Path)value); } if(URI.class.equals(type)) { return this.encode((URI)value); } if(URL.class.equals(type)) { return this.encode((URL)value); } if(Pattern.class.equals(type)) { return this.encode((Pattern)value); } if(InetAddress.class.isAssignableFrom(type)) { return this.encode((InetAddress)value); } if(Class.class.equals(type)) { return this.encode((Class)value); } throw new ConverterException("Can't encode " + type.getCanonicalName() + " to " + String.class.getCanonicalName()); } @SuppressWarnings("unchecked") @Override public String encode(T value, Type type) throws ConverterException { if(value == null) { return null; } if(type instanceof Class) { return this.encode(value, (Class)type); } else if(type instanceof GenericArrayType) { return this.encodeArray((Object[])value, ((GenericArrayType)type).getGenericComponentType()); } else if(type instanceof ParameterizedType) { ParameterizedType parameterizedType = ((ParameterizedType)type); if(parameterizedType.getActualTypeArguments().length == 1) { if(parameterizedType.getRawType() instanceof Class) { Class rawType = (Class)parameterizedType.getRawType(); Type typeArgument = parameterizedType.getActualTypeArguments()[0]; if(rawType.equals(Collection.class) || rawType.equals(List.class)) { return this.encodeList((List)value, typeArgument); } else if(rawType.equals(Set.class)) { return this.encodeSet((Set)value, typeArgument); } } } } throw new ConverterException("Can't encode " + type.getTypeName() + " to " + String.class.getCanonicalName()); } private String encodeCollection(Collection value) { return value != null ?value.stream().map(this::encode).collect(Collectors.joining(String.valueOf(this.arrayListSeparator))) : null; } private String encodeCollection(Collection value, Type type) { return value != null ? value.stream().map(element -> this.encode(element, type)).collect(Collectors.joining(String.valueOf(this.arrayListSeparator))) : null; } @Override public String encodeList(List value) { return this.encodeCollection(value); } @Override public String encodeList(List value, Class type) { return this.encodeCollection(value, type); } @Override public String encodeList(List value, Type type) { return this.encodeCollection(value, type); } @Override public String encodeSet(Set value) { return this.encodeCollection(value); } @Override public String encodeSet(Set value, Class type) { return this.encodeCollection(value, type); } @Override public String encodeSet(Set value, Type type) { return this.encodeCollection(value, type); } @Override public String encodeArray(T[] value) { if(value == null) { return null; } StringBuilder result = new StringBuilder(); for(int i = 0;i String encodeArray(T[] value, Class type) { return this.encodeArray(value, (Type)type); } @Override public String encodeArray(T[] value, Type type) { if(value == null) { return null; } StringBuilder result = new StringBuilder(); for(int i = 0;i value) throws ConverterException { return value != null ? value.getCanonicalName() : null; } @SuppressWarnings("unchecked") @Override public T decode(String value, Class type) { if(value == null) { return null; } if(CharSequence.class.isAssignableFrom(type)) { return (T) this.decodeString(value); } if(type.isArray()) { return (T) this.decodeToArray(value, type.getComponentType()); } if(Boolean.class.equals(type) || Boolean.TYPE.equals(type)) { return (T) this.decodeBoolean(value); } if(Character.class.equals(type) || Character.TYPE.equals(type)) { return (T) this.decodeCharacter(value); } if(Integer.class.equals(type) || Integer.TYPE.equals(type)) { return (T) this.decodeInteger(value); } if(Long.class.equals(type) || Long.TYPE.equals(type)) { return (T) this.decodeLong(value); } if(Byte.class.equals(type) || Byte.TYPE.equals(type)) { return (T) this.decodeByte(value); } if(Short.class.equals(type) || Short.TYPE.equals(type)) { return (T) this.decodeShort(value); } if(Float.class.equals(type) || Float.TYPE.equals(type)) { return (T) this.decodeFloat(value); } if(Double.class.equals(type) || Double.TYPE.equals(type)) { return (T) this.decodeDouble(value); } if(BigInteger.class.equals(type)) { return (T) this.decodeBigInteger(value); } if(BigDecimal.class.equals(type)) { return (T) this.decodeBigDecimal(value); } if(LocalDate.class.equals(type)) { return (T) this.decodeLocalDate(value); } if(LocalDateTime.class.equals(type)) { return (T) this.decodeLocalDateTime(value); } if(ZonedDateTime.class.equals(type)) { return (T) this.decodeZonedDateTime(value); } if(Currency.class.equals(type)) { return (T) this.decodeCurrency(value); } if(File.class.equals(type)) { return (T) this.decodeFile(value); } if(Path.class.equals(type)) { return (T) this.decodePath(value); } if(URI.class.equals(type)) { return (T) this.decodeURI(value); } if(URL.class.equals(type)) { return (T) this.decodeURL(value); } if(Pattern.class.equals(type)) { return (T) this.decodePattern(value); } if(Locale.class.equals(type)) { return (T) this.decodeLocale(value); } if(type.isEnum()) { return (T) this.decodeEnum(value, type.asSubclass(Enum.class)); } if(type.equals(Class.class)) { return (T) this.decodeClass(value); } if(InetAddress.class.isAssignableFrom(type)) { return (T) this.decodeInetAddress(value); } // TODO we could inject another String to object decoder based on json, xml... // to convert other types throw new ConverterException(value + " can't be decoded to the requested type: " + type.getCanonicalName()); } @SuppressWarnings("unchecked") @Override public T decode(String value, Type type) throws ConverterException { if(value == null) { return null; } if(type instanceof Class) { return this.decode(value, (Class)type); } else if(type instanceof GenericArrayType) { return (T) this.decodeToArray(value, ((GenericArrayType)type).getGenericComponentType()); } else if(type instanceof ParameterizedType) { ParameterizedType parameterizedType = ((ParameterizedType)type); if(parameterizedType.getActualTypeArguments().length == 1) { if(parameterizedType.getRawType() instanceof Class) { Class rawType = (Class)parameterizedType.getRawType(); Type typeArgument = parameterizedType.getActualTypeArguments()[0]; if(rawType.equals(Collection.class) || rawType.equals(List.class)) { return (T) this.decodeToList(value, typeArgument); } else if(rawType.equals(Set.class)) { return (T) this.decodeToSet(value, typeArgument); } } } } throw new ConverterException("Can't decode " + String.class.getCanonicalName() + " to " + type.getTypeName()); } @Override public List decodeToList(String value, Class type) throws ConverterException { return value != null ? this.decodeToList(value, (Type)type) : null; } @SuppressWarnings("unchecked") @Override public List decodeToList(String value, Type type) throws ConverterException { if(value == null) { return null; } return Arrays.stream(value.split(this.arrayListSeparator)).map(String::trim).map(item -> (T)this.decode(item, type)) .collect(Collectors.toList()); } @Override public Set decodeToSet(String value, Class type) throws ConverterException { return this.decodeToSet(value, (Type)type); } @SuppressWarnings("unchecked") @Override public Set decodeToSet(String value, Type type) throws ConverterException { if(value == null) { return null; } return Arrays.stream(value.split(this.arrayListSeparator)).map(String::trim).map(item -> (T)this.decode(item, type)) .collect(Collectors.toSet()); } @SuppressWarnings("unchecked") @Override public T[] decodeToArray(String value, Class type) throws ConverterException { if(value == null) { return null; } List objects = this.decodeToList(value, type); return objects.toArray((T[]) Array.newInstance(type, objects.size())); } @SuppressWarnings("unchecked") @Override public T[] decodeToArray(String value, Type type) throws ConverterException { if(value == null) { return null; } List objects = this.decodeToList(value, type); if(type instanceof Class) { return objects.toArray((T[]) Array.newInstance((Class)type, objects.size())); } else if(type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType)type; return objects.toArray((T[]) Array.newInstance((Class)parameterizedType.getRawType(), objects.size())); } else { throw new ConverterException("Can't decode " + String.class.getCanonicalName() + " to array of " + type.getTypeName()); } } @Override public Byte decodeByte(String value) throws ConverterException { try { return value != null ? Byte.valueOf(value) : null; } catch (NumberFormatException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Short decodeShort(String value) throws ConverterException { try { return value != null ? Short.valueOf(value) : null; } catch (NumberFormatException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Integer decodeInteger(String value) throws ConverterException { try { return value != null ? Integer.valueOf(value) : null; } catch (NumberFormatException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Long decodeLong(String value) throws ConverterException { try { return value != null ? Long.valueOf(value) : null; } catch (NumberFormatException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Float decodeFloat(String value) throws ConverterException { try { return value != null ? Float.valueOf(value) : null; } catch (NumberFormatException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Double decodeDouble(String value) throws ConverterException { try { return value != null ? Double.valueOf(value) : null; } catch (NumberFormatException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Character decodeCharacter(String value) throws ConverterException { if(value == null) { return null; } value = StringEscapeUtils.unescapeJava(value); if (value.length() == 1) { return value.charAt(0); } throw new ConverterException(value + " can't be decoded to the requested type"); } @Override public Boolean decodeBoolean(String value) throws ConverterException { return value != null ? Boolean.valueOf(value) : null; } @Override public String decodeString(String value) throws ConverterException { return StringEscapeUtils.unescapeJava(value); } @Override public BigInteger decodeBigInteger(String value) throws ConverterException { try { return value != null ? new BigInteger(value) : null; } catch (NumberFormatException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public BigDecimal decodeBigDecimal(String value) throws ConverterException { try { return value != null ? new BigDecimal(value) : null; } catch (NumberFormatException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public LocalDate decodeLocalDate(String value) throws ConverterException { try { return value != null ? LocalDate.parse(StringEscapeUtils.unescapeJava(value)) : null; } catch (Exception e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public LocalDateTime decodeLocalDateTime(String value) throws ConverterException { try { return value != null ? LocalDateTime.parse(StringEscapeUtils.unescapeJava(value)) : null; } catch (DateTimeParseException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public ZonedDateTime decodeZonedDateTime(String value) throws ConverterException { try { return value != null ? ZonedDateTime.parse(StringEscapeUtils.unescapeJava(value)) : null; } catch (DateTimeParseException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Currency decodeCurrency(String value) throws ConverterException { try { return value != null ? Currency.getInstance(StringEscapeUtils.unescapeJava(value)) : null; } catch (IllegalArgumentException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Locale decodeLocale(String value) throws ConverterException { if(value == null) { return null; } String[] elements = StringEscapeUtils.unescapeJava(value).split("_"); if (elements.length >= 1 && (elements[0].length() == 2 || elements[0].length() == 0)) { return new Locale(elements[0], elements.length >= 2 ? elements[1] : "", elements.length >= 3 ? elements[2] : ""); } throw new ConverterException(value + " can't be decoded to the requested type"); } @Override public File decodeFile(String value) throws ConverterException { return value != null ? new File(StringEscapeUtils.unescapeJava(value)) : null; } @Override public Path decodePath(String value) throws ConverterException { try { return value != null ? Path.of(StringEscapeUtils.unescapeJava(value)) : null; } catch (InvalidPathException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public URI decodeURI(String value) throws ConverterException { try { return value != null ? new URI(StringEscapeUtils.unescapeJava(value)) : null; } catch (URISyntaxException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public URL decodeURL(String value) throws ConverterException { try { return value != null ? new URL(StringEscapeUtils.unescapeJava(value)) : null; } catch (MalformedURLException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Pattern decodePattern(String value) throws ConverterException { try { return value != null ? Pattern.compile(StringEscapeUtils.unescapeJava(value)) : null; } catch (PatternSyntaxException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public InetAddress decodeInetAddress(String value) throws ConverterException { try { return value != null ? InetAddress.getByName(StringEscapeUtils.unescapeJava(value)) : null; } catch (UnknownHostException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } @Override public Class decodeClass(String value) throws ConverterException { try { return value != null ? Class.forName(StringEscapeUtils.unescapeJava(value)) : null; } catch (ClassNotFoundException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } private > T decodeEnum(String value, Class type) { try { return value != null ? Enum.valueOf(type, value) : null; } catch (IllegalArgumentException e) { throw new ConverterException(value + " can't be decoded to the requested type", e); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy