| /* |
| * Copyright (c) 2015, 2020 Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 2015 IBM Corporation. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // 02/19/2015 - Rick Curtis |
| // - 458877 : Add national character support |
| // 03/06/2015-2.7.0 Dalia Abo Sheasha |
| // - 461607: PropertiesUtils does not process methods with String parameters correctly. |
| // 05/06/2015-2.7.0 Rick Curtis |
| // - 466626: Fix bug in getMethods() when Java 2 security is enabled. |
| package org.eclipse.persistence.config; |
| |
| import java.lang.reflect.Method; |
| import java.security.AccessController; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.persistence.exceptions.ConversionException; |
| import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; |
| import org.eclipse.persistence.internal.security.PrivilegedGetMethods; |
| import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker; |
| |
| /** |
| * A static utility class that handles parsing a String |
| * "key=value,key1=value1...." and calls an appropriate set[key]([value]) method |
| * on the provided instance. |
| */ |
| public class PropertiesUtils { |
| /** |
| * Attempts to parse and then set the provided kvs String into the |
| * appropriate set method on the provided instance. |
| * |
| * Note: Keys and values cannot contain '=' or ',' |
| * |
| * @param instance |
| * An JavaBean instance |
| * @param propertyName |
| * The configuration name that is being set into instance. This |
| * is only used for informational purposes. |
| * @param kvs |
| * A String of key=value comma delimited ie: k1=v1,k2=v2,... |
| * @throws org.eclipse.persistence.exceptions.ConversionException |
| * if unable to process the provided kvs |
| */ |
| public static void set(Object instance, String propertyName, String kvs) { |
| if (instance == null || kvs == null || kvs.trim().isEmpty()) { |
| return; |
| } |
| String[] keyValues = kvs.split(","); |
| for (String kv : keyValues) { |
| processKeyValue(instance, propertyName, kv); |
| } |
| } |
| |
| private static void processKeyValue(Object instance, String propertyName, String kv) { |
| String[] t = kv.split("="); |
| |
| if (t.length != 2) { |
| // We must have a single key and a single value. |
| throw ConversionException.couldNotTranslatePropertiesIntoObject(instance, propertyName, kv, null); |
| } |
| String methodName = "set" + t[0].trim(); |
| // Stringified value to be set. Need to figure out it's type |
| String value = t[1].trim(); |
| List<Method> methods = getMethodsMatchingName(instance, methodName); |
| MethodMatch match = null; |
| try { |
| match = getMethodMatchingParameter(methods, value); |
| } catch (Exception e) { |
| throw ConversionException.couldNotTranslatePropertiesIntoObject(instance, propertyName, kv, e); |
| } |
| if (match != null) { |
| Method method = match.getMethod(); |
| Object parsedValue = match.getParsedValue(); |
| try { |
| invokeMethod(method, instance, parsedValue); |
| } catch (Exception e) { |
| throw ConversionException.couldNotTranslatePropertiesIntoObject(instance, propertyName, kv, e); |
| } |
| } else { |
| throw ConversionException.couldNotTranslatePropertiesIntoObject(instance, propertyName, kv, null); |
| } |
| } |
| |
| private static MethodMatch getMethodMatchingParameter(List<Method> methods, String parameter) throws Exception { |
| Object parsedParameterValue = null; |
| Method res = null; |
| for (Method method : methods) { |
| Class<?>[] params = method.getParameterTypes(); |
| if (params.length == 1) { |
| Class<?> param = params[0]; |
| if (param == String.class) { |
| parsedParameterValue = parameter; |
| } else if (param == Integer.class || param == int.class) { |
| parsedParameterValue = Integer.parseInt(parameter); |
| } else if (param == Boolean.class || param == boolean.class) { |
| // Don't use Boolean.parseBoolean(..) as it is to liberal |
| // with it's interpretation of false values |
| String lower = parameter.toLowerCase(); |
| if ("true".equals(lower)) { |
| parsedParameterValue = Boolean.TRUE; |
| } else if ("false".equals(lower)) { |
| parsedParameterValue = Boolean.FALSE; |
| } |
| } else if (param == Long.class || param == long.class) { |
| parsedParameterValue = Long.parseLong(parameter); |
| } else if (param == Float.class || param == float.class) { |
| parsedParameterValue = Float.parseFloat(parameter); |
| } else if (param == Double.class || param == double.class) { |
| parsedParameterValue = Double.parseDouble(parameter); |
| } |
| } |
| if (parsedParameterValue != null) { |
| return new MethodMatch(method, parsedParameterValue); |
| } |
| }// end for |
| return null; |
| } |
| |
| private static List<Method> getMethodsMatchingName(Object instance, String methodName) { |
| List<Method> methods = new ArrayList<>(); |
| for (Method method : getMethods(instance.getClass())) { |
| if (method.getName().equalsIgnoreCase(methodName)) { |
| methods.add(method); |
| } |
| } |
| return methods; |
| } |
| |
| private static Method[] getMethods(Class<?> cls) { |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| return AccessController.doPrivileged(new PrivilegedGetMethods(cls)); |
| } |
| return PrivilegedAccessHelper.getMethods(cls); |
| } |
| |
| private static Object invokeMethod(Method method, Object instance, Object... params) throws Exception { |
| if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()) { |
| return AccessController.doPrivileged(new PrivilegedMethodInvoker(method, instance, params)); |
| } |
| return method.invoke(instance, params); |
| } |
| |
| private static class MethodMatch { |
| final Method method; |
| final Object parsedValue; |
| |
| public MethodMatch(Method m, Object p) { |
| method = m; |
| parsedValue = p; |
| } |
| |
| public Method getMethod() { |
| return method; |
| } |
| |
| public Object getParsedValue() { |
| return parsedValue; |
| } |
| } |
| } |