Skip to content

Commit 39a2bdf

Browse files
committed
[java] Fixing InstanceCoercer to test properly for having a constructor in the target class (and code cleanup)
1 parent 1163f3e commit 39a2bdf

File tree

2 files changed

+59
-25
lines changed

2 files changed

+59
-25
lines changed

java/client/src/org/openqa/selenium/json/InstanceCoercer.java

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import java.lang.reflect.Modifier;
2626
import java.lang.reflect.ParameterizedType;
2727
import java.lang.reflect.Type;
28-
import java.util.ArrayList;
2928
import java.util.Arrays;
3029
import java.util.LinkedList;
3130
import java.util.List;
@@ -45,8 +44,12 @@ class InstanceCoercer extends TypeCoercer<Object> {
4544

4645
@Override
4746
public boolean test(Class aClass) {
48-
// If the class doesn't have a no-arg constructor, abandon hope
49-
return getConstructor(aClass) != null;
47+
try {
48+
getConstructor(aClass);
49+
return true;
50+
} catch (JsonException ex) {
51+
return false;
52+
}
5053
}
5154

5255
@Override
@@ -97,7 +100,7 @@ public BiFunction<JsonInput, PropertySetting, Object> apply(Type type) {
97100

98101
private Map<String, TypeAndWriter> getFieldWriters(Constructor<?> constructor) {
99102
List<Field> fields = new LinkedList<>();
100-
for (Class current = constructor.getDeclaringClass(); current != Object.class; current = current.getSuperclass()) {
103+
for (Class<?> current = constructor.getDeclaringClass(); current != Object.class; current = current.getSuperclass()) {
101104
fields.addAll(Arrays.asList(current.getDeclaredFields()));
102105
}
103106

@@ -109,17 +112,16 @@ private Map<String, TypeAndWriter> getFieldWriters(Constructor<?> constructor) {
109112
Collectors.toMap(
110113
Field::getName,
111114
field -> {
112-
TypeAndWriter tw = new TypeAndWriter();
113-
tw.type = field.getGenericType();
114-
tw.writer =
115+
Type type = field.getGenericType();
116+
BiConsumer<Object, Object> writer =
115117
(instance, value) -> {
116118
try {
117119
field.set(instance, value);
118120
} catch (IllegalAccessException e) {
119121
throw new JsonException(e);
120122
}
121123
};
122-
return tw;
124+
return new TypeAndWriter(type, writer);
123125
}));
124126
}
125127

@@ -131,9 +133,8 @@ private Map<String, TypeAndWriter> getBeanWriters(Constructor<?> constructor) {
131133
Collectors.toMap(
132134
SimplePropertyDescriptor::getName,
133135
desc -> {
134-
TypeAndWriter tw = new TypeAndWriter();
135-
tw.type = desc.getWriteMethod().getGenericParameterTypes()[0];
136-
tw.writer = (instance, value) -> {
136+
Type type = desc.getWriteMethod().getGenericParameterTypes()[0];
137+
BiConsumer<Object, Object>writer = (instance, value) -> {
137138
Method method = desc.getWriteMethod();
138139
method.setAccessible(true);
139140
try {
@@ -142,31 +143,31 @@ private Map<String, TypeAndWriter> getBeanWriters(Constructor<?> constructor) {
142143
throw new JsonException(e);
143144
}
144145
};
145-
return tw;
146+
return new TypeAndWriter(type, writer);
146147
}));
147148
}
148149

149150
private Constructor<?> getConstructor(Type type) {
150-
Class target = getClss(type);
151+
Class<?> target = getClss(type);
151152

152153
try {
153-
@SuppressWarnings("unchecked") Constructor<?> constructor = target.getDeclaredConstructor();
154+
Constructor<?> constructor = target.getDeclaredConstructor();
154155
constructor.setAccessible(true);
155156
return constructor;
156157
} catch (ReflectiveOperationException e) {
157158
throw new JsonException(e);
158159
}
159160
}
160161

161-
private static Class getClss(Type type) {
162-
Class target = null;
162+
private static Class<?> getClss(Type type) {
163+
Class<?> target = null;
163164

164165
if (type instanceof Class) {
165-
target = (Class) type;
166+
target = (Class<?>) type;
166167
} else if (type instanceof ParameterizedType) {
167168
Type rawType = ((ParameterizedType) type).getRawType();
168169
if (rawType instanceof Class) {
169-
target = (Class) rawType;
170+
target = (Class<?>) rawType;
170171
}
171172
}
172173

@@ -176,9 +177,14 @@ private static Class getClss(Type type) {
176177
return target;
177178
}
178179

179-
private class TypeAndWriter {
180-
public Type type;
181-
public BiConsumer<Object, Object> writer;
180+
private static class TypeAndWriter {
181+
private final Type type;
182+
private final BiConsumer<Object, Object> writer;
183+
184+
public TypeAndWriter(Type type, BiConsumer<Object, Object> writer) {
185+
this.type = type;
186+
this.writer = writer;
187+
}
182188
}
183189

184190
}

java/client/test/org/openqa/selenium/json/JsonTest.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@
4949
import static java.util.logging.Level.OFF;
5050
import static java.util.logging.Level.WARNING;
5151
import static org.assertj.core.api.Assertions.assertThat;
52+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
5253
import static org.assertj.core.api.Assertions.byLessThan;
54+
import static org.assertj.core.api.InstanceOfAssertFactories.MAP;
5355
import static org.openqa.selenium.Proxy.ProxyType.PAC;
5456
import static org.openqa.selenium.json.Json.MAP_TYPE;
5557
import static org.openqa.selenium.logging.LogType.BROWSER;
@@ -198,6 +200,16 @@ public void canPopulateASimpleBean() {
198200
assertThat(bean.getValue()).isEqualTo("time");
199201
}
200202

203+
@Test
204+
public void canNotPopulateAnObjectOfAClassWithNoDefaultConstructor() {
205+
String raw = "{\"value\": \"time\"}";
206+
207+
assertThatExceptionOfType(JsonException.class)
208+
.isThrownBy(() -> new Json().toType(raw, NoDefaultConstructor.class))
209+
.withMessageStartingWith(
210+
"Unable to find type coercer for class %s", NoDefaultConstructor.class.getTypeName());
211+
}
212+
201213
@Test
202214
public void willSilentlyDiscardUnusedFieldsWhenPopulatingABean() {
203215
String raw = "{\"value\": \"time\", \"frob\": \"telephone\"}";
@@ -263,8 +275,8 @@ public void shouldConvertAResponseWithAnElementInIt() {
263275
"{\"value\":{\"value\":\"\",\"text\":\"\",\"selected\":false,\"enabled\":true,\"id\":\"three\"},\"context\":\"con\",\"sessionId\":\"sess\"}";
264276
Response converted = new Json().toType(json, Response.class);
265277

266-
Map<String, Object> value = (Map<String, Object>) converted.getValue();
267-
assertThat(value).containsEntry("id", "three");
278+
assertThat(converted).extracting("value").asInstanceOf(MAP)
279+
.containsEntry("id", "three");
268280
}
269281

270282
@Test
@@ -310,8 +322,7 @@ public void shouldConvertObjectsInArraysToMaps() {
310322
Object first = list.get(0);
311323
assertThat(first instanceof Map).isTrue();
312324

313-
Map<String, Object> map = (Map<String, Object>) first;
314-
assertThat(map)
325+
assertThat(first).asInstanceOf(MAP)
315326
.containsEntry("name", "foo")
316327
.containsEntry("value", "bar")
317328
.containsEntry("domain", "localhost")
@@ -540,6 +551,23 @@ public void setValue(String value) {
540551
}
541552
}
542553

554+
public static class NoDefaultConstructor {
555+
556+
private String value;
557+
558+
public NoDefaultConstructor(String value) {
559+
this.value = value;
560+
}
561+
562+
public String getValue() {
563+
return value;
564+
}
565+
566+
public void setValue(String value) {
567+
this.value = value;
568+
}
569+
}
570+
543571
public static class ContainingBean {
544572

545573
private String name;

0 commit comments

Comments
 (0)