Skip to content

Commit 1428380

Browse files
jamezpVerdent
authored andcommittedMar 13, 2025
[599] Add better support for resolution of wildcard types.
Signed-off-by: James R. Perkins <jperkins@redhat.com>
1 parent 9e9f43f commit 1428380

File tree

7 files changed

+270
-4
lines changed

7 files changed

+270
-4
lines changed
 

‎src/main/java/org/eclipse/yasson/internal/ReflectionUtils.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -190,6 +190,10 @@ public static Type resolveItemVariableType(List<Type> chain, TypeVariable<?> typ
190190
if (tmp != null) {
191191
returnType = tmp;
192192
}
193+
// If the type is a WildcardType we need to resolve the most specific type
194+
if (returnType instanceof WildcardType) {
195+
return resolveMostSpecificBound(chain, (WildcardType) returnType, warn);
196+
}
193197
if (!(returnType instanceof TypeVariable)) {
194198
break;
195199
}

‎src/main/java/org/eclipse/yasson/internal/deserializer/DeserializationModelCreator.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -233,7 +233,7 @@ private ModelDeserializer<JsonParser> createObjectDeserializer(LinkedList<Type>
233233
if (creatorModel.getCustomization().isRequired()) {
234234
defaultCreatorValues.put(parameterName, new RequiredCreatorParameter(parameterName));
235235
} else {
236-
Class<?> rawParamType = ReflectionUtils.getRawType(creatorModel.getType());
236+
Class<?> rawParamType = ReflectionUtils.getOptionalRawType(creatorModel.getType()).orElse(Object.class);
237237
defaultCreatorValues.put(parameterName, DEFAULT_CREATOR_VALUES.getOrDefault(rawParamType, NULL_PROVIDER));
238238
}
239239
}

‎src/test/java/org/eclipse/yasson/defaultmapping/generics/GenericsTest.java

+40-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2023 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,6 +13,7 @@
1313
package org.eclipse.yasson.defaultmapping.generics;
1414

1515
import java.lang.reflect.Type;
16+
import java.lang.reflect.WildcardType;
1617
import java.math.BigDecimal;
1718
import java.text.ParseException;
1819
import java.text.SimpleDateFormat;
@@ -36,8 +37,11 @@
3637
import org.eclipse.yasson.defaultmapping.generics.model.AnotherGenericTestClass;
3738
import org.eclipse.yasson.defaultmapping.generics.model.BoundedGenericClass;
3839
import org.eclipse.yasson.defaultmapping.generics.model.Circle;
40+
import org.eclipse.yasson.defaultmapping.generics.model.CollectionContainer;
41+
import org.eclipse.yasson.defaultmapping.generics.model.CollectionElement;
3942
import org.eclipse.yasson.defaultmapping.generics.model.CollectionWrapper;
4043
import org.eclipse.yasson.defaultmapping.generics.model.ColoredCircle;
44+
import org.eclipse.yasson.defaultmapping.generics.model.ConstructorContainer;
4145
import org.eclipse.yasson.defaultmapping.generics.model.CyclicSubClass;
4246
import org.eclipse.yasson.defaultmapping.generics.model.FinalGenericWrapper;
4347
import org.eclipse.yasson.defaultmapping.generics.model.FinalMember;
@@ -49,6 +53,7 @@
4953
import org.eclipse.yasson.defaultmapping.generics.model.MyCyclicGenericClass;
5054
import org.eclipse.yasson.defaultmapping.generics.model.PropagatedGenericClass;
5155
import org.eclipse.yasson.defaultmapping.generics.model.Shape;
56+
import org.eclipse.yasson.defaultmapping.generics.model.StaticCreatorContainer;
5257
import org.eclipse.yasson.defaultmapping.generics.model.WildCardClass;
5358
import org.eclipse.yasson.defaultmapping.generics.model.WildcardMultipleBoundsClass;
5459
import org.eclipse.yasson.serializers.model.Box;
@@ -474,6 +479,40 @@ public void lowerBoundTypeVariableInCollectionAttribute() throws Exception {
474479
assertEquals(6, fromJson.get(0).field1);
475480

476481
}
482+
483+
@Test
484+
public void genericConstructorCreator() {
485+
final String expectedJson = "{\"value\":\"Test\"}";
486+
final ConstructorContainer<String> container = new ConstructorContainer<>("Test");
487+
488+
assertEquals(expectedJson, defaultJsonb.toJson(container));
489+
assertEquals(container, defaultJsonb.fromJson(expectedJson, ConstructorContainer.class));
490+
}
491+
492+
@Test
493+
public void genericStaticCreator() {
494+
final String expectedJson = "{\"value\":\"static\"}";
495+
final StaticCreatorContainer<String> container = StaticCreatorContainer.create("static");
496+
497+
assertEquals(expectedJson, defaultJsonb.toJson(container));
498+
assertEquals(container, defaultJsonb.fromJson(expectedJson, StaticCreatorContainer.class));
499+
}
500+
501+
@Test
502+
public void wildcardCollectionContainer() {
503+
final String expectedJson = "{\"collection\":{\"collection\":[{\"wrapped\":\"wrappedElement\"}]}}";
504+
final CollectionContainer collectionContainer = new CollectionContainer();
505+
final CollectionWrapper<CollectionElement<?>> collectionWrapper = new CollectionWrapper<>();
506+
final CollectionElement<String> wildcardType = new CollectionElement<>();
507+
wildcardType.setWrapped("wrappedElement");
508+
final Collection<CollectionElement<?>> list = List.of(wildcardType);
509+
collectionWrapper.setCollection(list);
510+
collectionContainer.setCollection(collectionWrapper);
511+
512+
assertEquals(expectedJson, defaultJsonb.toJson(collectionContainer));
513+
final CollectionContainer result = defaultJsonb.fromJson(expectedJson, CollectionContainer.class);
514+
assertEquals(collectionContainer, result);
515+
}
477516

478517
public interface FunctionalInterface<T> {
479518
T getValue();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2025 Red Hat, Inc. and/or its affiliates.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0,
7+
* or the Eclipse Distribution License v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
13+
package org.eclipse.yasson.defaultmapping.generics.model;
14+
15+
import java.util.Collection;
16+
import java.util.Objects;
17+
18+
/**
19+
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
20+
*/
21+
public class CollectionContainer {
22+
23+
private CollectionWrapper<CollectionElement<?>> collection;
24+
25+
public CollectionWrapper<CollectionElement<?>> getCollection() {
26+
return collection;
27+
}
28+
29+
public void setCollection(final CollectionWrapper<CollectionElement<?>> collection) {
30+
this.collection = collection;
31+
}
32+
33+
@Override
34+
public boolean equals(final Object obj) {
35+
if (obj == this) {
36+
return true;
37+
}
38+
if (!(obj instanceof CollectionContainer)) {
39+
return false;
40+
}
41+
final CollectionContainer other = (CollectionContainer) obj;
42+
final Collection<CollectionElement<?>> thisCollection = collection.getCollection();
43+
final Collection<CollectionElement<?>> otherCollection = other.collection.getCollection();
44+
if (thisCollection == null && otherCollection == null) {
45+
return true;
46+
}
47+
if (thisCollection == null || otherCollection == null) {
48+
return false;
49+
}
50+
return thisCollection.containsAll(otherCollection) && otherCollection.containsAll(thisCollection);
51+
}
52+
53+
@Override
54+
public int hashCode() {
55+
return Objects.hash(collection);
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2025 Red Hat, Inc. and/or its affiliates.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0,
7+
* or the Eclipse Distribution License v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
13+
package org.eclipse.yasson.defaultmapping.generics.model;
14+
15+
import java.util.Objects;
16+
17+
/**
18+
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
19+
*/
20+
public class CollectionElement<T> {
21+
22+
private T wrapped;
23+
24+
public T getWrapped() {
25+
return wrapped;
26+
}
27+
28+
public void setWrapped(T wrapped) {
29+
this.wrapped = wrapped;
30+
}
31+
32+
@Override
33+
public int hashCode() {
34+
return Objects.hash(wrapped);
35+
}
36+
37+
@Override
38+
public boolean equals(final Object obj) {
39+
if (this == obj) {
40+
return true;
41+
}
42+
if (!(obj instanceof CollectionElement)) {
43+
return false;
44+
}
45+
final CollectionElement<?> other = (CollectionElement<?>) obj;
46+
return Objects.equals(wrapped, other.wrapped);
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2025 Red Hat, Inc. and/or its affiliates.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0,
7+
* or the Eclipse Distribution License v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
13+
package org.eclipse.yasson.defaultmapping.generics.model;
14+
15+
import java.util.Objects;
16+
17+
import jakarta.json.bind.annotation.JsonbCreator;
18+
import jakarta.json.bind.annotation.JsonbProperty;
19+
20+
/**
21+
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
22+
*/
23+
public class ConstructorContainer<T> {
24+
25+
private final T value;
26+
27+
@JsonbCreator
28+
public ConstructorContainer(@JsonbProperty("value") final T value) {
29+
this.value = value;
30+
}
31+
32+
public T getValue() {
33+
return value;
34+
}
35+
36+
@Override
37+
public String toString() {
38+
return "ConstructorContainer[value=" + value + "]";
39+
}
40+
41+
@Override
42+
public int hashCode() {
43+
return Objects.hash(value);
44+
}
45+
46+
@Override
47+
public boolean equals(final Object obj) {
48+
if (this == obj) {
49+
return true;
50+
}
51+
if (!(obj instanceof ConstructorContainer)) {
52+
return false;
53+
}
54+
final ConstructorContainer<?> other = (ConstructorContainer<?>) obj;
55+
return Objects.equals(value, other.value);
56+
}
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2025 Red Hat, Inc. and/or its affiliates.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0,
7+
* or the Eclipse Distribution License v. 1.0 which is available at
8+
* http://www.eclipse.org/org/documents/edl-v10.php.
9+
*
10+
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
11+
*/
12+
13+
package org.eclipse.yasson.defaultmapping.generics.model;
14+
15+
import java.util.Objects;
16+
17+
import jakarta.json.bind.annotation.JsonbCreator;
18+
import jakarta.json.bind.annotation.JsonbProperty;
19+
20+
/**
21+
* @author <a href="mailto:jperkins@redhat.com">James R. Perkins</a>
22+
*/
23+
public class StaticCreatorContainer<T> {
24+
private final T value;
25+
26+
private StaticCreatorContainer(T value) {
27+
this.value = value;
28+
}
29+
30+
@JsonbCreator
31+
public static <T> StaticCreatorContainer<T> create(@JsonbProperty("value") final T value) {
32+
return new StaticCreatorContainer<>(value);
33+
}
34+
35+
public T getValue() {
36+
return value;
37+
}
38+
39+
@Override
40+
public String toString() {
41+
return "StaticCreatorContainer[value=" + value + "]";
42+
}
43+
44+
@Override
45+
public int hashCode() {
46+
return Objects.hash(value);
47+
}
48+
49+
@Override
50+
public boolean equals(final Object obj) {
51+
if (this == obj) {
52+
return true;
53+
}
54+
if (!(obj instanceof StaticCreatorContainer)) {
55+
return false;
56+
}
57+
final StaticCreatorContainer<?> other = (StaticCreatorContainer<?>) obj;
58+
return Objects.equals(value, other.value);
59+
}
60+
61+
}

0 commit comments

Comments
 (0)
Please sign in to comment.