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

org.apache.pulsar.common.util.FieldParser Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.apache.pulsar.common.util;

import static org.apache.pulsar.shade.com.google.common.base.Preconditions.checkArgument;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
import org.apache.pulsar.shade.com.fasterxml.jackson.databind.AnnotationIntrospector;
import org.apache.pulsar.shade.com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import org.apache.pulsar.shade.com.fasterxml.jackson.databind.util.EnumResolver;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.pulsar.shade.org.apache.commons.lang3.StringUtils;

/**
 * Generic value converter.
 *
 * 

Use examples

* *
 * String o1 = String.valueOf(1);
 * ;
 * Integer i = FieldParser.convert(o1, Integer.class);
 * System.out.println(i); // 1
 *
 * 
* */ public final class FieldParser { private static final Map CONVERTERS = new HashMap<>(); private static final Map, Class> WRAPPER_TYPES = new HashMap<>(); private static final AnnotationIntrospector ANNOTATION_INTROSPECTOR = new JacksonAnnotationIntrospector(); static { // Preload converters and wrapperTypes. initConverters(); initWrappers(); } /** * Convert the given object value to the given class. * * @param from * The object value to be converted. * @param to * The type class which the given object should be converted to. * @return The converted object value. * @throws UnsupportedOperationException * If no suitable converter can be found. * @throws RuntimeException * If conversion failed somehow. This can be caused by at least an ExceptionInInitializerError, * IllegalAccessException or InvocationTargetException. */ @SuppressWarnings("unchecked") public static T convert(Object from, Class to) { requireNonNull(to); if (from == null) { return null; } to = (Class) wrap(to); // Can we cast? Then just do it. if (to.isAssignableFrom(from.getClass())) { return to.cast(from); } // Lookup the suitable converter. String converterId = from.getClass().getName() + "_" + to.getName(); Method converter = CONVERTERS.get(converterId); if (to.isEnum()) { // Converting string to enum EnumResolver r = EnumResolver.constructUsingToString((Class>) to, ANNOTATION_INTROSPECTOR); T value = (T) r.findEnum((String) from); if (value == null) { throw new RuntimeException("Invalid value '" + from + "' for enum " + to); } return value; } if (converter == null) { throw new UnsupportedOperationException("Cannot convert from " + from.getClass().getName() + " to " + to.getName() + ". Requested converter does not exist."); } // Convert the value. try { Object val = converter.invoke(to, from); return to.cast(val); } catch (Exception e) { throw new RuntimeException("Cannot convert from " + from.getClass().getName() + " to " + to.getName() + ". Conversion failed with " + e.getMessage(), e); } } /** * Update given Object attribute by reading it from provided map properties. * * @param properties * which key-value pair of properties to assign those values to given object * @param obj * object which needs to be updated * @throws IllegalArgumentException * if the properties key-value contains incorrect value type */ public static void update(Map properties, T obj) throws IllegalArgumentException { Field[] fields = obj.getClass().getDeclaredFields(); Arrays.stream(fields).forEach(f -> { if (properties.containsKey(f.getName())) { try { f.setAccessible(true); String v = properties.get(f.getName()); if (!StringUtils.isBlank(v)) { f.set(obj, value(trim(v), f)); } else { setEmptyValue(v, f, obj); } } catch (Exception e) { throw new IllegalArgumentException(format("failed to initialize %s field while setting value %s", f.getName(), properties.get(f.getName())), e); } } }); } /** * Converts value as per appropriate DataType of the field. * * @param strValue * : string value of the object * @param field * : field of the attribute * @return */ public static Object value(String strValue, Field field) { requireNonNull(field); // if field is not primitive type Type fieldType = field.getGenericType(); if (fieldType instanceof ParameterizedType) { Class clazz = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0]; if (field.getType().equals(List.class)) { // convert to list return stringToList(strValue, clazz); } else if (field.getType().equals(Set.class)) { // covert to set return stringToSet(strValue, clazz); } else if (field.getType().equals(Map.class)) { Class valueClass = (Class) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[1]; return stringToMap(strValue, clazz, valueClass); } else if (field.getType().equals(Optional.class)) { Type typeClazz = ((ParameterizedType) fieldType).getActualTypeArguments()[0]; if (typeClazz instanceof ParameterizedType) { throw new IllegalArgumentException(format("unsupported non-primitive Optional<%s> for %s", typeClazz.getClass(), field.getName())); } return Optional.ofNullable(convert(strValue, (Class) typeClazz)); } else { throw new IllegalArgumentException( format("unsupported field-type %s for %s", field.getType(), field.getName())); } } else { return convert(strValue, field.getType()); } } /** * Sets the empty/null value if field is allowed to be set empty. * * @param strValue * @param field * @param obj * @throws IllegalArgumentException * @throws IllegalAccessException */ public static void setEmptyValue(String strValue, Field field, T obj) throws IllegalArgumentException, IllegalAccessException { requireNonNull(field); // if field is not primitive type Type fieldType = field.getGenericType(); if (fieldType instanceof ParameterizedType) { if (field.getType().equals(List.class)) { field.set(obj, new ArrayList<>()); } else if (field.getType().equals(Set.class)) { field.set(obj, new LinkedHashSet<>()); } else if (field.getType().equals(Optional.class)) { field.set(obj, Optional.empty()); } else { throw new IllegalArgumentException( format("unsupported field-type %s for %s", field.getType(), field.getName())); } } else if (Number.class.isAssignableFrom(field.getType()) || fieldType.getClass().equals(String.class)) { field.set(obj, null); } } private static Class wrap(Class type) { return WRAPPER_TYPES.containsKey(type) ? WRAPPER_TYPES.get(type) : type; } private static void initConverters() { Method[] methods = FieldParser.class.getDeclaredMethods(); Arrays.stream(methods).forEach(method -> { if (method.getParameterTypes().length == 1) { // Converter should accept 1 argument. This skips the convert() method. CONVERTERS.put(method.getParameterTypes()[0].getName() + "_" + method.getReturnType().getName(), method); } }); } private static void initWrappers() { WRAPPER_TYPES.put(int.class, Integer.class); WRAPPER_TYPES.put(float.class, Float.class); WRAPPER_TYPES.put(double.class, Double.class); WRAPPER_TYPES.put(long.class, Long.class); WRAPPER_TYPES.put(boolean.class, Boolean.class); } /***** --- Converters --- ****/ /** * Converts String to Integer. * * @param val * The String to be converted. * @return The converted Integer value. */ public static Integer stringToInteger(String val) { String v = trim(val); if (org.apache.pulsar.shade.io.netty.util.internal.StringUtil.isNullOrEmpty(v)) { return null; } else { return Integer.valueOf(v); } } /** * Converts String to Long. * * @param val * The String to be converted. * @return The converted Long value. */ public static Long stringToLong(String val) { return Long.valueOf(trim(val)); } /** * Converts String to Double. * * @param val * The String to be converted. * @return The converted Double value. */ public static Double stringToDouble(String val) { String v = trim(val); if (org.apache.pulsar.shade.io.netty.util.internal.StringUtil.isNullOrEmpty(v)) { return null; } else { return Double.valueOf(v); } } /** * Converts String to float. * * @param val * The String to be converted. * @return The converted Double value. */ public static Float stringToFloat(String val) { return Float.valueOf(trim(val)); } /** * Converts comma separated string to List. * * @param * type of list * @param val * comma separated values. * @return The converted list with type {@code }. */ public static List stringToList(String val, Class type) { if (val == null) { return null; } String[] tokens = trim(val).split(","); return Arrays.stream(tokens).map(t -> { return convert(trim(t), type); }).collect(Collectors.toList()); } /** * Converts comma separated string to Set. * * @param * type of set * @param val * comma separated values. * @return The converted set with type {@code }. */ public static Set stringToSet(String val, Class type) { if (val == null) { return null; } String[] tokens = trim(val).split(","); return Arrays.stream(tokens).map(t -> { return convert(trim(t), type); }).collect(Collectors.toCollection(LinkedHashSet::new)); } private static Map stringToMap(String strValue, Class keyType, Class valueType) { if (strValue == null) { return null; } String[] tokens = trim(strValue).split(","); Map map = new HashMap<>(); for (String token : tokens) { String[] keyValue = trim(token).split("="); checkArgument(keyValue.length == 2, strValue + " map-value is not in correct format key1=value,key2=value2"); map.put(convert(trim(keyValue[0]), keyType), convert(trim(keyValue[1]), valueType)); } return map; } private static String trim(String val) { requireNonNull(val); return val.trim(); } /** * Converts Integer to String. * * @param value * The Integer to be converted. * @return The converted String value. */ public static String integerToString(Integer value) { return value.toString(); } /** * Converts Boolean to String. * * @param value * The Boolean to be converted. * @return The converted String value. */ public static String booleanToString(Boolean value) { return value.toString(); } /** * Converts String to Boolean. * * @param value * The String to be converted. * @return The converted Boolean value. */ public static Boolean stringToBoolean(String value) { return Boolean.valueOf(value); } // implement more converter methods here. }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy