ValueHandler.java revision 1870:4aa2e64eff30
1351280Sdim/*
2351280Sdim * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3351280Sdim * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4351280Sdim *
5351280Sdim * This code is free software; you can redistribute it and/or modify it
6351280Sdim * under the terms of the GNU General Public License version 2 only, as
7351280Sdim * published by the Free Software Foundation.
8351280Sdim *
9351280Sdim * This code is distributed in the hope that it will be useful, but WITHOUT
10351280Sdim * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11351280Sdim * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12351280Sdim * version 2 for more details (a copy is included in the LICENSE file that
13351280Sdim * accompanied this code).
14360784Sdim *
15351280Sdim * You should have received a copy of the GNU General Public License version
16351280Sdim * 2 along with this work; if not, write to the Free Software Foundation,
17351280Sdim * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18351280Sdim *
19351280Sdim * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20351280Sdim * or visit www.oracle.com if you need additional information or have any
21351280Sdim * questions.
22351280Sdim */
23351280Sdim
24351280Sdimpackage jdk.test.failurehandler.value;
25351280Sdim
26351280Sdimimport jdk.test.failurehandler.Utils;
27351280Sdim
28351280Sdimimport java.lang.reflect.Field;
29351280Sdimimport java.lang.reflect.Modifier;
30351280Sdimimport java.util.Objects;
31351280Sdimimport java.util.Properties;
32351280Sdim
33351280Sdimpublic final class ValueHandler {
34351280Sdim    public static <T> void apply(T object, Properties properties,
35351280Sdim                                 String prefix) throws InvalidValueException {
36351280Sdim        Objects.requireNonNull(object, "object cannot be null");
37351280Sdim        Objects.requireNonNull(properties, "properties cannot be null");
38351280Sdim        Class<?> aClass = object.getClass();
39351280Sdim        while (aClass != null) {
40351280Sdim            for (Field field : aClass.getDeclaredFields()) {
41351280Sdim                Value p = field.getAnnotation(Value.class);
42351280Sdim                if (p != null) {
43351280Sdim                    applyToField(p, object, field, properties, prefix);
44351280Sdim                } else {
45351280Sdim                    SubValues sub
46351280Sdim                            = field.getAnnotation(SubValues.class);
47351280Sdim                    if (sub != null) {
48351280Sdim                        getAccess(field);
49351280Sdim                        try {
50351280Sdim                            apply(field.get(object), properties,
51351280Sdim                                    Utils.prependPrefix(prefix, sub.prefix()));
52351280Sdim                        } catch (IllegalAccessException e) {
53351280Sdim                            throw new InvalidValueException(String.format(
54351280Sdim                                    "can't apply sub properties to %s.",
55351280Sdim                                    field.getName()));
56351280Sdim                        }
57351280Sdim                    }
58351280Sdim                }
59351280Sdim            }
60351280Sdim            aClass = aClass.getSuperclass();
61351280Sdim        }
62351280Sdim    }
63351280Sdim
64351280Sdim    private static void applyToField(Value property, Object object,
65351280Sdim                Field field, Properties properties, String prefix)
66351280Sdim            throws InvalidValueException {
67351280Sdim        getAccess(field);
68351280Sdim        if (Modifier.isFinal(field.getModifiers())) {
69351280Sdim            throw new InvalidValueException(
70351280Sdim                    String.format("field '%s' is final", field));
71351280Sdim        }
72351280Sdim        String name = Utils.prependPrefix(prefix, property.name());
73351280Sdim        String value = getProperty(properties, prefix, property.name());
74351280Sdim        if (value == null) {
75351280Sdim            DefaultValue defaultValue
76351280Sdim                    = field.getAnnotation(DefaultValue.class);
77351280Sdim            value = defaultValue == null ? null : defaultValue.value();
78351280Sdim        }
79351280Sdim        if (value == null) {
80351280Sdim            throw new InvalidValueException(String.format(
81351280Sdim                    "can't set '%s', because properties don't have '%s'.",
82351280Sdim                    field.getName(), name));
83351280Sdim        }
84351280Sdim        String delimiter = getProperty(properties,
85351280Sdim                Utils.prependPrefix(prefix, property.name()), "delimiter");
86351280Sdim        delimiter = delimiter == null ? " " : delimiter;
87351280Sdim        Class<? extends ValueParser> parserClass = property.parser();
88351280Sdim        try {
89351280Sdim            field.set(object, parserClass.newInstance().parse(
90351280Sdim                    field.getType(), value, delimiter));
91351280Sdim        } catch (ReflectiveOperationException | IllegalArgumentException e) {
92351280Sdim            throw new InvalidValueException(
93351280Sdim                    String.format("can't set field '%s' : %s",
94351280Sdim                            field.getName(), e.getMessage()), e);
95351280Sdim        }
96351280Sdim    }
97351280Sdim
98351280Sdim    private static String getProperty(Properties properties,
99351280Sdim                                      String prefix, String name) {
100351280Sdim        if (prefix == null || prefix.isEmpty()) {
101351280Sdim            return properties.getProperty(name);
102360784Sdim        }
103360784Sdim        int index = prefix.length();
104360784Sdim        do {
105360784Sdim            String value = properties.getProperty(
106360784Sdim                    Utils.prependPrefix(prefix.substring(0, index), name));
107351280Sdim            if (value != null) {
108351280Sdim                return value;
109351280Sdim            }
110351280Sdim            index = prefix.lastIndexOf('.', index - 1);
111351280Sdim        } while (index > 0);
112351280Sdim        return  properties.getProperty(name);
113351280Sdim    }
114351280Sdim
115351280Sdim    private static void getAccess(Field field) {
116351280Sdim        int modifiers = field.getModifiers();
117351280Sdim        if (!Modifier.isPublic(modifiers)) {
118351280Sdim            field.setAccessible(true);
119351280Sdim        }
120351280Sdim    }
121351280Sdim
122351280Sdim}
123351280Sdim