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

burningwave / reflection / #68

18 Oct 2023 11:19AM UTC coverage: 74.528% (+5.4%) from 69.107%
#68

push

Roberto-Gentili
Bug fix

790 of 1060 relevant lines covered (74.53%)

0.75 hits per line

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

64.52
/src/main/java/org/burningwave/reflection/Constructors.java
1
/*
2
 * This file is part of Burningwave Reflection.
3
 *
4
 * Author: Roberto Gentili
5
 *
6
 * Hosted at: https://github.com/burningwave/reflection
7
 *
8
 * --
9
 *
10
 * The MIT License (MIT)
11
 *
12
 * Copyright (c) 2022 Roberto Gentili
13
 *
14
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
15
 * documentation files (the "Software"), to deal in the Software without restriction, including without
16
 * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
17
 * the Software, and to permit persons to whom the Software is furnished to do so, subject to the following
18
 * conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all copies or substantial
21
 * portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24
 * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25
 * EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
27
 * OR OTHER DEALINGS IN THE SOFTWARE.
28
 */
29
package org.burningwave.reflection;
30

31

32
import java.lang.invoke.MethodHandle;
33
import java.lang.invoke.MethodHandles;
34
import java.lang.invoke.MethodType;
35
import java.lang.reflect.Constructor;
36
import java.util.ArrayList;
37
import java.util.Arrays;
38
import java.util.Collection;
39
import java.util.stream.Collectors;
40

41
import org.burningwave.Classes;
42
import org.burningwave.Executor;
43
import org.burningwave.Throwables;
44

45

46
@SuppressWarnings("unchecked")
47
public class Constructors extends Members.Handler.OfExecutable<Constructor<?>, ConstructorCriteria>  {
48
        public final static Constructors INSTANCE;
49

50
        static {
51
                INSTANCE = new Constructors();
1✔
52
        }
1✔
53

54
        private Constructors() {}
1✔
55

56
        public Collection<Constructor<?>> findAllAndMakeThemAccessible(
57
                Class<?> targetClass
58
        ) {
59
                Collection<Constructor<?>> members = Cache.INSTANCE.uniqueKeyForConstructors.getOrUploadIfAbsent(
×
60
                                getCacheKey(targetClass, Members.ALL_FOR_CLASS), () -> {
×
61
                                return findAllAndApply(
×
62
                                        ConstructorCriteria.withoutConsideringParentClasses(), targetClass, (member) ->
×
63
                                        setAccessible(member, true)
×
64
                                );
65
                        }
66
                );
67
                return members;
×
68
        }
69

70
        public Collection<Constructor<?>> findAllAndMakeThemAccessible(
71
                Class<?> targetClass,
72
                Class<?>... inputParameterTypesOrSubTypes
73
        ) {
74
                String cacheKey = getCacheKey(targetClass, Members.ALL_FOR_CLASS + " by input parameters assignable from", inputParameterTypesOrSubTypes);
1✔
75
                return Cache.INSTANCE.uniqueKeyForConstructors.getOrUploadIfAbsent(cacheKey, () -> {
1✔
76
                        ConstructorCriteria criteria = ConstructorCriteria.withoutConsideringParentClasses().parameterTypesAreAssignableFrom(inputParameterTypesOrSubTypes);
1✔
77
                        if (inputParameterTypesOrSubTypes != null && inputParameterTypesOrSubTypes.length == 0) {
1✔
78
                                criteria.or().parameter((parameters, idx) -> parameters.length == 1 && parameters[0].isVarArgs());
1✔
79
                        }
80
                        return findAllAndApply(
1✔
81
                                criteria,
82
                                targetClass,
83
                                (member) ->
84
                                        setAccessible(member, true)
1✔
85
                        );
86
                });
87
        }
88

89
        public MethodHandle findDirectHandle(Class<?> targetClass, Class<?>... inputParameterTypesOrSubTypes) {
90
                return findDirectHandleBox(targetClass, inputParameterTypesOrSubTypes).getHandler();
×
91
        }
92

93
        public Constructor<?> findFirstAndMakeItAccessible(Class<?> targetClass, Class<?>... inputParameterTypesOrSubTypes) {
94
                Collection<Constructor<?>> members = findAllAndMakeThemAccessible(targetClass, inputParameterTypesOrSubTypes);
1✔
95
                if (members.size() == 1) {
1✔
96
                        return members.stream().findFirst().get();
1✔
97
                } else if (members.size() > 1) {
×
98
                        Collection<Constructor<?>> membersThatMatch = searchForExactMatch(members, inputParameterTypesOrSubTypes);
×
99
                        if (!membersThatMatch.isEmpty()) {
×
100
                                return membersThatMatch.stream().findFirst().get();
×
101
                        }
102
                        return members.stream().findFirst().get();
×
103
                }
104
                return null;
×
105
        }
106

107
        public Constructor<?> findOneAndMakeItAccessible(Class<?> targetClass, Class<?>... argumentTypes) {
108
                Collection<Constructor<?>> members = findAllAndMakeThemAccessible(targetClass, argumentTypes);
1✔
109
                if (members.size() == 1) {
1✔
110
                        return members.stream().findFirst().get();
1✔
111
                } else if (members.size() > 1) {
×
112
                        Collection<Constructor<?>> membersThatMatch = searchForExactMatch(members, argumentTypes);
×
113
                        if (membersThatMatch.size() == 1) {
×
114
                                return membersThatMatch.stream().findFirst().get();
×
115
                        }
116
                        Throwables.INSTANCE.throwException(
×
117
                                "Found more than one of constructor with argument types {} in {} class",
118
                                String.join(", ", Arrays.asList(argumentTypes).stream().map(cls -> cls.getName()).collect(Collectors.toList())),
×
119
                                targetClass.getName()
×
120
                        );
121
                }
122
                return null;
×
123
        }
124

125
        public <T> T newInstanceOf(
126
                Class<?> targetClass,
127
                Object... arguments
128
        ) {
129
                return Executor.getFirst(
1✔
130
                        () -> {
131
                                Class<?>[] argsType = Classes.INSTANCE.retrieveFrom(arguments);
1✔
132
                                Members.Handler.OfExecutable.Box<Constructor<?>> methodHandleBox = findDirectHandleBox(targetClass, argsType);
1✔
133
                                return Executor.get(() -> {
1✔
134
                                                Constructor<?> ctor = methodHandleBox.getExecutable();
1✔
135
                                                return (T)methodHandleBox.getHandler().invokeWithArguments(
1✔
136
                                                        getFlatArgumentList(ctor, ArrayList::new, arguments)
1✔
137
                                                );
138
                                        }
139
                                );
140
                        }, () -> {
141
                                Constructor<?> ctor = findFirstAndMakeItAccessible(targetClass, Classes.INSTANCE.retrieveFrom(arguments));
1✔
142
                                if (ctor == null) {
1✔
143
                                        Throwables.INSTANCE.throwException("Constructor not found in {}", targetClass.getName());
×
144
                                }
145
                                return (T)Facade.INSTANCE.newInstance(
1✔
146
                                        ctor,
147
                                        getArgumentArray(
1✔
148
                                                ctor,
149
                                                this::getArgumentListWithArrayForVarArgs,
150
                                                ArrayList::new,
151
                                                arguments
152
                                        )
153
                                );
154
                        }
155
                );
156

157
        }
158

159
        @Override
160
        MethodHandle retrieveMethodHandle(MethodHandles.Lookup consulter, Constructor<?> constructor) throws NoSuchMethodException, IllegalAccessException {
161
                return consulter.findConstructor(
1✔
162
                        constructor.getDeclaringClass(),
1✔
163
                        MethodType.methodType(void.class, constructor.getParameterTypes())
1✔
164
                );
165
        }
166

167
        String retrieveNameForCaching(Class<?> cls) {
168
                return Classes.INSTANCE.retrieveSimpleName(cls.getName());
1✔
169
        }
170

171
        @Override
172
        String retrieveNameForCaching(Constructor<?> constructor) {
173
                return retrieveNameForCaching(constructor.getDeclaringClass());
1✔
174
        }
175

176
        private Members.Handler.OfExecutable.Box<Constructor<?>> findDirectHandleBox(Class<?> targetClass, Class<?>... inputParameterTypesOrSubTypes) {
177
                String nameForCaching = retrieveNameForCaching(targetClass);
1✔
178
                String cacheKey = getCacheKey(targetClass, "equals " + nameForCaching, inputParameterTypesOrSubTypes);
1✔
179
                Members.Handler.OfExecutable.Box<Constructor<?>> entry =
1✔
180
                        (Box<Constructor<?>>)Cache.INSTANCE.uniqueKeyForExecutableAndMethodHandle.get(cacheKey);
1✔
181
                if (entry == null) {
1✔
182
                        Constructor<?> ctor = findFirstAndMakeItAccessible(targetClass, inputParameterTypesOrSubTypes);
1✔
183
                        entry = findDirectHandleBox(
1✔
184
                                ctor, cacheKey
185
                        );
186
                }
187
                return entry;
1✔
188
        }
189
}
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