/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * See LICENSE.txt included in this distribution for the specific * language governing permissions and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at LICENSE.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. */ package org.opengrok.indexer.util; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.logging.Level; import java.util.logging.Logger; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.lang3.BooleanUtils; import org.opengrok.indexer.logger.LoggerFactory; /** * * @author Krystof Tulinger */ public class ClassUtil { private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class); private ClassUtil() { } /** * Mark all transient fields in {@code targetClass} as @Transient for the * XML serialization. * * Fields marked with java transient keyword do not work because the * XMLEncoder does not take these into account. This helper marks the fields * marked with transient keyword as transient also for the XMLDecoder. * * @param targetClass the class */ public static void remarkTransientFields(Class> targetClass) { try { BeanInfo info = Introspector.getBeanInfo(targetClass); PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors(); for (Field f : targetClass.getDeclaredFields()) { if (Modifier.isTransient(f.getModifiers())) { for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { if (propertyDescriptor.getName().equals(f.getName())) { propertyDescriptor.setValue("transient", Boolean.TRUE); } } } } } catch (IntrospectionException ex) { LOGGER.log(Level.WARNING, "An exception occurred during remarking transient fields:", ex); } } private static Object stringToObject(String fieldName, Class> c, String value) throws IOException { Object v; String paramClass = c.getName(); try { /* * Java primitive types as per * java * datatypes. */ if (paramClass.equals("boolean") || paramClass.equals(Boolean.class.getName())) { Boolean parsedValue = BooleanUtils.toBooleanObject(value); if (parsedValue == null) { throw new IOException(String.format("Unsupported type conversion from String to a boolean for name \"%s\" -" + " got \"%s\" - allowed values are [false, off, 0, true, on, 1].", paramClass, value)); } v = parsedValue; } else if (paramClass.equals("short") || paramClass.equals(Short.class.getName())) { v = Short.valueOf(value); } else if (paramClass.equals("int") || paramClass.equals(Integer.class.getName())) { v = Integer.valueOf(value); } else if (paramClass.equals("long") || paramClass.equals(Long.class.getName())) { v = Long.valueOf(value); } else if (paramClass.equals("float") || paramClass.equals(Float.class.getName())) { v = Float.valueOf(value); } else if (paramClass.equals("double") || paramClass.equals(Double.class.getName())) { v = Double.valueOf(value); } else if (paramClass.equals("byte") || paramClass.equals(Byte.class.getName())) { v = Byte.valueOf(value); } else if (paramClass.equals("char") || paramClass.equals(Character.class.getName())) { v = value.charAt(0); } else if (paramClass.equals(String.class.getName())) { v = value; } else { ObjectMapper mapper = new ObjectMapper(); v = mapper.readValue(value, c); } } catch (NumberFormatException ex) { throw new IOException( String.format("Unsupported type conversion from String to a number for name \"%s\" - %s.", fieldName, ex.getLocalizedMessage()), ex); } catch (IndexOutOfBoundsException ex) { throw new IOException( String.format("The string is not long enough to extract 1 character for name \"%s\" - %s.", fieldName, ex.getLocalizedMessage()), ex); } return v; } private static Method getSetter(Object obj, String fieldName) throws IOException { PropertyDescriptor desc; try { desc = new PropertyDescriptor(fieldName, obj.getClass()); } catch (IntrospectionException e) { throw new IOException(e); } Method setter = desc.getWriteMethod(); if (setter == null) { throw new IOException( String.format("No setter for the name \"%s\".", fieldName)); } if (setter.getParameterCount() != 1) { // not a setter /* * Actually should not happen as it is not considered as a * writer method so an exception would be thrown earlier. */ throw new IOException( String.format("The setter \"%s\" for the name \"%s\" does not take exactly 1 parameter.", setter.getName(), fieldName)); } return setter; } /** * Invokes a setter on an object and passes a value to that setter. * * The value is passed as string and the function will automatically try to * convert it to the parameter type in the setter. These conversion are * available only for * java * primitive datatypes: *