• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

oracle / opengrok / #3642

23 Oct 2023 02:33PM UTC coverage: 75.784% (+1.4%) from 74.413%
#3642

push

web-flow
Sonar code smell issue fixes (#4450)

Signed-off-by: Gino Augustine <ginoaugustine@gmail.com>

200 of 200 new or added lines in 39 files covered. (100.0%)

44390 of 58574 relevant lines covered (75.78%)

0.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

45.45
/opengrok-indexer/src/main/java/org/opengrok/indexer/util/ClassUtil.java
1
/*
2
 * CDDL HEADER START
3
 *
4
 * The contents of this file are subject to the terms of the
5
 * Common Development and Distribution License (the "License").
6
 * You may not use this file except in compliance with the License.
7
 *
8
 * See LICENSE.txt included in this distribution for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing Covered Code, include this CDDL HEADER in each
12
 * file and include the License file at LICENSE.txt.
13
 * If applicable, add the following below this CDDL HEADER, with the
14
 * fields enclosed by brackets "[]" replaced with your own identifying
15
 * information: Portions Copyright [yyyy] [name of copyright owner]
16
 *
17
 * CDDL HEADER END
18
 */
19

20
/*
21
 * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
22
 */
23
package org.opengrok.indexer.util;
24

25
import java.beans.BeanInfo;
26
import java.beans.IntrospectionException;
27
import java.beans.Introspector;
28
import java.beans.PropertyDescriptor;
29
import java.io.IOException;
30
import java.lang.reflect.Field;
31
import java.lang.reflect.InvocationTargetException;
32
import java.lang.reflect.Method;
33
import java.lang.reflect.Modifier;
34
import java.util.logging.Level;
35
import java.util.logging.Logger;
36

37
import com.fasterxml.jackson.databind.ObjectMapper;
38
import org.apache.commons.lang3.BooleanUtils;
39
import org.opengrok.indexer.logger.LoggerFactory;
40

41
/**
42
 *
43
 * @author Krystof Tulinger
44
 */
45
public class ClassUtil {
46

47
    private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);
1✔
48

49
    private ClassUtil() {
50
    }
51

52
    /**
53
     * Mark all transient fields in {@code targetClass} as @Transient for the
54
     * XML serialization.
55
     *
56
     * Fields marked with java transient keyword do not work because the
57
     * XMLEncoder does not take these into account. This helper marks the fields
58
     * marked with transient keyword as transient also for the XMLDecoder.
59
     *
60
     * @param targetClass the class
61
     */
62
    public static void remarkTransientFields(Class<?> targetClass) {
63
        try {
64
            BeanInfo info = Introspector.getBeanInfo(targetClass);
1✔
65
            PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
1✔
66
            for (Field f : targetClass.getDeclaredFields()) {
1✔
67
                if (Modifier.isTransient(f.getModifiers())) {
1✔
68
                    for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
1✔
69
                        if (propertyDescriptor.getName().equals(f.getName())) {
1✔
70
                            propertyDescriptor.setValue("transient", Boolean.TRUE);
1✔
71
                        }
72
                    }
73
                }
74
            }
75
        } catch (IntrospectionException ex) {
×
76
            LOGGER.log(Level.WARNING, "An exception occurred during remarking transient fields:", ex);
×
77
        }
1✔
78
    }
1✔
79

80
    private static Object stringToObject(String fieldName, Class<?> c, String value) throws IOException {
81
        Object v;
82
        String paramClass = c.getName();
1✔
83

84
        try {
85
            /*
86
             * Java primitive types as per
87
             * <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html">java
88
             * datatypes</a>.
89
             */
90
            if (paramClass.equals("boolean") || paramClass.equals(Boolean.class.getName())) {
1✔
91
                Boolean parsedValue = BooleanUtils.toBooleanObject(value);
×
92
                if (parsedValue == null) {
×
93
                    throw new IOException(String.format("Unsupported type conversion from String to a boolean for name \"%s\" -"
×
94
                                    + " got \"%s\" - allowed values are [false, off, 0, true, on, 1].",
95
                            paramClass, value));
96
                }
97
                v = parsedValue;
×
98
            } else if (paramClass.equals("short") || paramClass.equals(Short.class.getName())) {
1✔
99
                v = Short.valueOf(value);
×
100
            } else if (paramClass.equals("int") || paramClass.equals(Integer.class.getName())) {
1✔
101
                v = Integer.valueOf(value);
1✔
102
            } else if (paramClass.equals("long") || paramClass.equals(Long.class.getName())) {
1✔
103
                v = Long.valueOf(value);
×
104
            } else if (paramClass.equals("float") || paramClass.equals(Float.class.getName())) {
1✔
105
                v = Float.valueOf(value);
×
106
            } else if (paramClass.equals("double") || paramClass.equals(Double.class.getName())) {
1✔
107
                v = Double.valueOf(value);
×
108
            } else if (paramClass.equals("byte") || paramClass.equals(Byte.class.getName())) {
1✔
109
                v = Byte.valueOf(value);
×
110
            } else if (paramClass.equals("char") || paramClass.equals(Character.class.getName())) {
1✔
111
                v = value.charAt(0);
×
112
            } else if (paramClass.equals(String.class.getName())) {
1✔
113
                v = value;
1✔
114
            } else {
115
                ObjectMapper mapper = new ObjectMapper();
1✔
116
                v = mapper.readValue(value, c);
1✔
117
            }
118
        }  catch (NumberFormatException ex) {
×
119
            throw new IOException(
×
120
                    String.format("Unsupported type conversion from String to a number for name \"%s\" - %s.",
×
121
                            fieldName, ex.getLocalizedMessage()), ex);
×
122
        } catch (IndexOutOfBoundsException ex) {
×
123
            throw new IOException(
×
124
                    String.format("The string is not long enough to extract 1 character for name \"%s\" - %s.",
×
125
                            fieldName, ex.getLocalizedMessage()), ex);
×
126
        }
1✔
127

128
        return v;
1✔
129
    }
130

131
    private static Method getSetter(Object obj, String fieldName) throws IOException {
132
        PropertyDescriptor desc;
133
        try {
134
            desc = new PropertyDescriptor(fieldName, obj.getClass());
1✔
135
        } catch (IntrospectionException e) {
×
136
            throw new IOException(e);
×
137
        }
1✔
138
        Method setter = desc.getWriteMethod();
1✔
139

140
        if (setter == null) {
1✔
141
            throw new IOException(
×
142
                    String.format("No setter for the name \"%s\".", fieldName));
×
143
        }
144

145
        if (setter.getParameterCount() != 1) {
1✔
146
            // not a setter
147
            /*
148
             * Actually should not happen as it is not considered as a
149
             * writer method so an exception would be thrown earlier.
150
             */
151
            throw new IOException(
×
152
                    String.format("The setter \"%s\" for the name \"%s\" does not take exactly 1 parameter.",
×
153
                            setter.getName(), fieldName));
×
154
        }
155

156
        return setter;
1✔
157
    }
158

159
    /**
160
     * Invokes a setter on an object and passes a value to that setter.
161
     *
162
     * The value is passed as string and the function will automatically try to
163
     * convert it to the parameter type in the setter. These conversion are
164
     * available only for
165
     * <a href="https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html">java
166
     * primitive datatypes</a>:
167
     * <ul>
168
     * <li>Boolean or boolean</li>
169
     * <li>Short or short</li>
170
     * <li>Integer or integer</li>
171
     * <li>Long or long</li>
172
     * <li>Float or float</li>
173
     * <li>Double or double</li>
174
     * <li>Byte or byte</li>
175
     * <li>Character or char</li>
176
     * <li>String</li>
177
     * </ul>
178
     * Any other parameter type will cause an exception. The size/value itself is checked elsewhere.
179
     *
180
     * @param obj the object
181
     * @param fieldName name of the field which will be changed
182
     * @param value desired value represented as string
183
     *
184
     * @throws IOException if any error occurs (no suitable method, bad conversion, ...)
185
     */
186
    public static void setFieldValue(Object obj, String fieldName, String value) throws IOException {
187
        Method setter = getSetter(obj, fieldName);
1✔
188
        Class<?> c = setter.getParameterTypes()[0];
1✔
189
        Object objValue = stringToObject(fieldName, c, value);
1✔
190
        invokeSetter(setter, obj, fieldName, objValue);
1✔
191
    }
1✔
192

193
    /**
194
     * Invokes a setter on an object and passes a value to that setter.
195
     *
196
     * @param obj the object
197
     * @param fieldName name of the field which will be changed
198
     * @param value desired value
199
     * @throws IOException all exceptions from the reflection
200
     */
201
    public static void setFieldValue(Object obj, String fieldName, Object value) throws IOException {
202
        Method setter = getSetter(obj, fieldName);
×
203
        invokeSetter(setter, obj, fieldName, value);
×
204
    }
×
205

206
    private static void invokeSetter(Method setter, Object obj, String fieldName, Object value) throws IOException {
207
        try {
208
            setter.invoke(obj, value);
1✔
209
        } catch (IllegalAccessException
×
210
                | IllegalArgumentException
211
                /*
212
                 * This the case when the invocation failed because the invoked
213
                 * method failed with an exception. All exceptions are
214
                 * propagated through this exception.
215
                 */
216
                | InvocationTargetException ex) {
217
            throw new IOException(
×
218
                    String.format("Unsupported operation with object of class %s for name \"%s\" - %s.",
×
219
                            obj.getClass().toString(),
×
220
                            fieldName,
221
                            ex.getCause() == null
×
222
                                    ? ex.getLocalizedMessage()
×
223
                                    : ex.getCause().getLocalizedMessage()), ex);
×
224
        }
1✔
225
    }
1✔
226

227
    /**
228
     * @param obj object
229
     * @param fieldName field name
230
     * @return true if field is present in the object (not recursively) or false
231
     */
232
    public static boolean hasField(Object obj, String fieldName) {
233
        try {
234
            new PropertyDescriptor(fieldName, obj.getClass());
×
235
        } catch (IntrospectionException e) {
×
236
            return false;
×
237
        }
×
238
        return true;
×
239
    }
240

241
    /**
242
     * Invokes a getter of a property on an object.
243
     *
244
     * @param obj the object
245
     * @param field string with field name
246
     * @return string representation of the field value
247
     * @throws java.io.IOException exception
248
     */
249
    public static Object getFieldValue(Object obj, String field) throws IOException {
250

251
        try {
252
            PropertyDescriptor desc = new PropertyDescriptor(field, obj.getClass());
1✔
253
            Method getter = desc.getReadMethod();
1✔
254

255
            if (getter == null) {
1✔
256
                throw new IOException(
×
257
                        String.format("No getter for the name \"%s\".", field));
×
258
            }
259

260
            if (getter.getParameterCount() != 0) {
1✔
261
                /*
262
                 * Actually should not happen as it is not considered as a
263
                 * read method so an exception would be thrown earlier.
264
                 */
265
                throw new IOException(
×
266
                        String.format("The getter \"%s\" for the name \"%s\" takes a parameter.",
×
267
                                getter.getName(), field));
×
268
            }
269

270
            return getter.invoke(obj);
1✔
271
        } catch (IntrospectionException
×
272
                | IllegalAccessException
273
                | InvocationTargetException
274
                | IllegalArgumentException ex) {
275
            throw new IOException(
×
276
                    String.format("Unsupported operation with object of class %s for name \"%s\" - %s.",
×
277
                            obj.getClass().toString(),
×
278
                            field,
279
                            ex.getCause() == null
×
280
                            ? ex.getLocalizedMessage()
×
281
                            : ex.getCause().getLocalizedMessage()),
×
282
                    ex);
283
        }
284
    }
285
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc