1+ package com .datadog .api .compatibility ;
2+
3+ import com .fasterxml .jackson .core .type .TypeReference ;
4+ import com .fasterxml .jackson .databind .JsonNode ;
5+ import com .fasterxml .jackson .databind .ObjectMapper ;
6+ import org .junit .Test ;
7+
8+ import java .io .IOException ;
9+ import java .util .List ;
10+
11+ import static org .junit .Assert .*;
12+
13+ /**
14+ * CRITICAL TEST: This demonstrates the exact Java 8 compilation issue that PR #4191 would have caused.
15+ *
16+ * This test contains BOTH the problematic pattern AND the fixed pattern to prove our solution works.
17+ */
18+ public class DiamondOperatorCompilationTest {
19+
20+ private final ObjectMapper objectMapper = new ObjectMapper ();
21+
22+ @ Test
23+ public void testJava8DiamondOperatorIssueReproduction () throws IOException {
24+ // This test reproduces the EXACT issue from PR #4191
25+
26+ String jsonArray = "[{\" email\" : \" test@example.com\" }, {\" role\" : \" viewer\" }]" ;
27+ JsonNode tree = objectMapper .readTree (jsonArray );
28+
29+ // ❌ PROBLEMATIC PATTERN (would fail compilation in Java 8):
30+ // The following line would cause this compilation error:
31+ // "cannot infer type arguments for com.fasterxml.jackson.core.type.TypeReference<T>
32+ // reason: '<>' with anonymous inner classes is not supported in -source 8"
33+ //
34+ // Object tmp = tree.traverse(objectMapper).readValueAs(new TypeReference<>() {});
35+ // ^^
36+ // Diamond operator fails!
37+
38+ // ✅ FIXED PATTERN (works in Java 8):
39+ Object tmp = tree .traverse (objectMapper ).readValueAs (new TypeReference <List <Object >>() {});
40+
41+ assertNotNull (tmp );
42+ assertTrue ("Should deserialize successfully with explicit type" , tmp instanceof List );
43+
44+ @ SuppressWarnings ("unchecked" )
45+ List <Object > result = (List <Object >) tmp ;
46+ assertEquals ("Should have 2 elements" , 2 , result .size ());
47+ }
48+
49+ @ Test
50+ public void testTemplateFixSimulation () throws IOException {
51+ // This simulates what our template fix does:
52+ // Detects parameterized types and uses explicit TypeReference
53+
54+ String jsonData = "[1.5, 2.0, 3.7]" ; // Numbers (like DistributionPointItem)
55+ JsonNode tree = objectMapper .readTree (jsonData );
56+
57+ // Template logic simulation:
58+ String dataType = "List<Double>" ;
59+ String unParameterizedDataType = "Double" ; // This would be different, so use TypeReference
60+
61+ boolean isParameterized = !dataType .equals (unParameterizedDataType );
62+ assertTrue ("Template should detect this as parameterized" , isParameterized );
63+
64+ // Because it's parameterized, template generates this (FIXED pattern):
65+ Object tmp = tree .traverse (objectMapper ).readValueAs (new TypeReference <List <Double >>() {});
66+ // Instead of this (BROKEN pattern that would fail):
67+ // Object tmp = tree.traverse(objectMapper).readValueAs(new TypeReference<>() {});
68+
69+ assertNotNull (tmp );
70+ assertTrue (tmp instanceof List );
71+
72+ @ SuppressWarnings ("unchecked" )
73+ List <Double > result = (List <Double >) tmp ;
74+ assertEquals (3 , result .size ());
75+ assertEquals (1.5 , result .get (0 ), 0.001 );
76+ }
77+
78+ @ Test
79+ public void testOriginalSharedDashboardInvitesDataScenario () throws IOException {
80+ // This recreates the exact failing scenario from SharedDashboardInvitesData.java:138
81+
82+ String jsonInvites = "[{\" email\" :\" user@example.com\" ,\" role\" :\" viewer\" }]" ;
83+ JsonNode tree = objectMapper .readTree (jsonInvites );
84+
85+ // BEFORE our fix (would cause Java 8 compilation failure):
86+ // tmp = tree.traverse(jp.getCodec()).readValueAs(new TypeReference<>() {});
87+
88+ // AFTER our fix (Java 8 compatible):
89+ Object tmp = tree .traverse (objectMapper )
90+ .readValueAs (new TypeReference <List <Object >>() {});
91+
92+ assertNotNull ("Should deserialize invite data" , tmp );
93+ assertTrue ("Should be a List" , tmp instanceof List );
94+
95+ @ SuppressWarnings ("unchecked" )
96+ List <Object > invites = (List <Object >) tmp ;
97+ assertEquals ("Should have one invite" , 1 , invites .size ());
98+ }
99+
100+ @ Test
101+ public void testOriginalDistributionPointItemScenario () throws IOException {
102+ // This recreates the exact failing scenario from DistributionPointItem.java:132
103+
104+ String jsonPoints = "[1.0, 2.5, 3.14]" ; // Distribution points as numbers
105+ JsonNode tree = objectMapper .readTree (jsonPoints );
106+
107+ // BEFORE our fix (would cause Java 8 compilation failure):
108+ // tmp = tree.traverse(jp.getCodec()).readValueAs(new TypeReference<>() {});
109+
110+ // AFTER our fix (Java 8 compatible):
111+ Object tmp = tree .traverse (objectMapper )
112+ .readValueAs (new TypeReference <List <Double >>() {});
113+
114+ assertNotNull ("Should deserialize distribution points" , tmp );
115+ assertTrue ("Should be a List" , tmp instanceof List );
116+
117+ @ SuppressWarnings ("unchecked" )
118+ List <Double > points = (List <Double >) tmp ;
119+ assertEquals ("Should have 3 points" , 3 , points .size ());
120+ assertEquals ("First point should be 1.0" , 1.0 , points .get (0 ), 0.001 );
121+ }
122+
123+ @ Test
124+ public void testCustomAttributeValuesUnionScenario () throws IOException {
125+ // This recreates what CustomAttributeValuesUnion.java:133 would have been
126+
127+ String jsonValues = "[\" string_value\" , 42, {\" object\" : \" value\" }]" ; // Mixed values
128+ JsonNode tree = objectMapper .readTree (jsonValues );
129+
130+ // BEFORE our fix (would cause Java 8 compilation failure):
131+ // tmp = tree.traverse(jp.getCodec()).readValueAs(new TypeReference<>() {});
132+
133+ // AFTER our fix (Java 8 compatible):
134+ Object tmp = tree .traverse (objectMapper )
135+ .readValueAs (new TypeReference <List <Object >>() {});
136+
137+ assertNotNull ("Should deserialize custom attribute values" , tmp );
138+ assertTrue ("Should be a List" , tmp instanceof List );
139+
140+ @ SuppressWarnings ("unchecked" )
141+ List <Object > values = (List <Object >) tmp ;
142+ assertEquals ("Should have 3 values" , 3 , values .size ());
143+ }
144+
145+ @ Test
146+ public void testCompilationDifferenceDocumentation () {
147+ // This test documents the exact difference between failing and working code
148+
149+ // ❌ FAILS in Java 8 (diamond operator with anonymous inner class):
150+ String failingPattern = "new TypeReference<>() {}" ;
151+
152+ // ✅ WORKS in Java 8 (explicit type parameters):
153+ String workingPattern1 = "new TypeReference<List<String>>() {}" ;
154+ String workingPattern2 = "new TypeReference<List<Object>>() {}" ;
155+ String workingPattern3 = "new TypeReference<List<Double>>() {}" ;
156+
157+ // Verify the patterns
158+ assertTrue ("Failing pattern uses diamond operator" , failingPattern .contains ("<>" ));
159+
160+ assertFalse ("Working pattern 1 should not use diamond operator" , workingPattern1 .contains ("<>" ));
161+ assertFalse ("Working pattern 2 should not use diamond operator" , workingPattern2 .contains ("<>" ));
162+ assertFalse ("Working pattern 3 should not use diamond operator" , workingPattern3 .contains ("<>" ));
163+
164+ // All working patterns have explicit types
165+ assertTrue ("Pattern 1 has explicit type" , workingPattern1 .contains ("List<String>" ));
166+ assertTrue ("Pattern 2 has explicit type" , workingPattern2 .contains ("List<Object>" ));
167+ assertTrue ("Pattern 3 has explicit type" , workingPattern3 .contains ("List<Double>" ));
168+ }
169+ }
0 commit comments