Skip to content

Commit 8cc2789

Browse files
committed
server: Only serialize supported value types in OutputElementStyle
This will make sure that only objects that comply with the TSP specification are serialized. Added unit tests to verify this. eclipse-cdt-cloud/trace-server-protocol#102 Signed-off-by: Bernd Hufmann <[email protected]>
1 parent 060e98c commit 8cc2789

File tree

3 files changed

+203
-2
lines changed

3 files changed

+203
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Ericsson and others
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License 2.0 which
6+
* accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*******************************************************************************/
11+
12+
package org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.webapp;
13+
14+
import org.junit.Before;
15+
16+
import com.fasterxml.jackson.databind.ObjectMapper;
17+
18+
/**
19+
* Abstract test class for testing serializers
20+
*
21+
* @author Bernd Hufmann
22+
*/
23+
public class AbstractSerializerTest {
24+
25+
/**
26+
* A object mapper to be used for serialization / deserialization. A new
27+
* instance is created per test case.
28+
*/
29+
protected ObjectMapper fMapper;
30+
31+
/**
32+
* Test setup
33+
*/
34+
@Before
35+
public void setup() {
36+
fMapper = new ObjectMapper();
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2025 Ericsson and others
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License 2.0 which
6+
* accompanies this distribution, and is available at
7+
* https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*******************************************************************************/
11+
12+
package org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.webapp;
13+
14+
import static org.junit.Assert.assertEquals;
15+
import static org.junit.Assert.assertNotNull;
16+
import static org.junit.Assert.assertTrue;
17+
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
import java.util.Map.Entry;
21+
22+
import org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.webapp.OutputElementStyleSerializer;
23+
import org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core.tests.stubs.OutputElementStyleStub;
24+
import org.eclipse.tracecompass.tmf.core.model.OutputElementStyle;
25+
import org.eclipse.tracecompass.tmf.core.model.StyleProperties;
26+
import org.junit.Test;
27+
28+
import com.fasterxml.jackson.core.JsonProcessingException;
29+
import com.fasterxml.jackson.databind.module.SimpleModule;
30+
31+
/**
32+
* Test the {@link OutputElementStyleSerializer}
33+
*
34+
* @author Bernd Hufmann
35+
*/
36+
public class OutputElementStyleSerializerTest extends AbstractSerializerTest {
37+
38+
private static final String VALID_STYLE_NAME = "valid-styles";
39+
private static final String MAPPED_STYLE_NAME = "mapped-styles";
40+
private static final String INVALID_STYLE_NAME = "invalid-styles";
41+
42+
/**
43+
* Verify that valid style objects are serialized properly
44+
*
45+
* @throws JsonProcessingException
46+
* if an error occurs
47+
*/
48+
@SuppressWarnings("null")
49+
@Test
50+
public void testValidStyles() throws JsonProcessingException {
51+
Map<String, Object> validStyles = new HashMap<>();
52+
validStyles.put(StyleProperties.BACKGROUND_COLOR, "ffffff");
53+
validStyles.put(StyleProperties.LINEAR_GRADIENT, "true");
54+
validStyles.put(StyleProperties.OPACITY, 0.4f);
55+
validStyles.put(StyleProperties.WIDTH, Integer.valueOf(4));
56+
57+
SimpleModule module = new SimpleModule();
58+
module.addSerializer(OutputElementStyle.class, new OutputElementStyleSerializer());
59+
fMapper.registerModule(module);
60+
61+
OutputElementStyle testStyle = new OutputElementStyle(VALID_STYLE_NAME, validStyles);
62+
String json = fMapper.writeValueAsString(testStyle);
63+
64+
OutputElementStyleStub deserialized = fMapper.readValue(json, OutputElementStyleStub.class);
65+
assertEquals(testStyle.getParentKey(), deserialized.getParentKey());
66+
67+
verifyStyles(testStyle, deserialized);
68+
}
69+
70+
/**
71+
* Verify that certain types of style objects are serialized properly, e.g. Long
72+
* are casted to Integer
73+
*
74+
* @throws JsonProcessingException
75+
* if an error occurs
76+
*/
77+
@SuppressWarnings("null")
78+
@Test
79+
public void testMappedStyles() throws JsonProcessingException {
80+
Map<String, Object> mappedStyles = new HashMap<>();
81+
mappedStyles.put(StyleProperties.LINEAR_GRADIENT, "true");
82+
mappedStyles.put(StyleProperties.OPACITY, 0.4d);
83+
mappedStyles.put("long-style", Long.valueOf(1234));
84+
mappedStyles.put("byte-style", Byte.valueOf((byte) 5));
85+
86+
SimpleModule module = new SimpleModule();
87+
module.addSerializer(OutputElementStyle.class, new OutputElementStyleSerializer());
88+
fMapper.registerModule(module);
89+
90+
OutputElementStyle testStyle = new OutputElementStyle(MAPPED_STYLE_NAME, mappedStyles);
91+
String json = fMapper.writeValueAsString(testStyle);
92+
93+
OutputElementStyleStub deserialized = fMapper.readValue(json, OutputElementStyleStub.class);
94+
assertEquals(testStyle.getParentKey(), deserialized.getParentKey());
95+
96+
verifyStyles(testStyle, deserialized);
97+
}
98+
99+
/**
100+
* Verify that types of style objects that are not specified in the TSP are not serialized properly
101+
*
102+
* @throws JsonProcessingException
103+
* if an error occurs
104+
*/
105+
@SuppressWarnings("null")
106+
@Test
107+
public void testInvalidStyles() throws JsonProcessingException {
108+
Map<String, Object> invalidStyles = new HashMap<>();
109+
invalidStyles.put("ignore-invalid", invalidStyles);
110+
invalidStyles.put("ingore-long-style1", Long.valueOf(Long.MIN_VALUE));
111+
invalidStyles.put("ingore-long-style2", Long.valueOf(Long.MAX_VALUE));
112+
113+
SimpleModule module = new SimpleModule();
114+
module.addSerializer(OutputElementStyle.class, new OutputElementStyleSerializer());
115+
fMapper.registerModule(module);
116+
117+
OutputElementStyle testStyle = new OutputElementStyle(INVALID_STYLE_NAME, invalidStyles);
118+
String json = fMapper.writeValueAsString(testStyle);
119+
120+
OutputElementStyleStub deserialized = fMapper.readValue(json, OutputElementStyleStub.class);
121+
assertEquals(testStyle.getParentKey(), deserialized.getParentKey());
122+
assertTrue(deserialized.getStyleValues().isEmpty());
123+
}
124+
125+
private static void verifyStyles(OutputElementStyle testStyle, OutputElementStyleStub deserialized) {
126+
for (Entry<String, Object> entry : testStyle.getStyleValues().entrySet()) {
127+
Map<String, Object> styleValues = deserialized.getStyleValues();
128+
assertNotNull(styleValues);
129+
String key = entry.getKey();
130+
Object entryValue = entry.getValue();
131+
assertTrue(key, styleValues.containsKey(key));
132+
if (entryValue instanceof Float || entryValue instanceof Double) {
133+
assertEquals(key, Double.valueOf(entryValue.toString()), styleValues.get(key));
134+
} else if (entryValue instanceof Number longValue) {
135+
assertEquals(key, longValue.intValue(), styleValues.get(key));
136+
} else {
137+
assertEquals(key, entryValue, styleValues.get(key));
138+
}
139+
}
140+
}
141+
142+
}

trace-server/org.eclipse.tracecompass.incubator.trace.server.jersey.rest.core/src/org/eclipse/tracecompass/incubator/internal/trace/server/jersey/rest/core/webapp/OutputElementStyleSerializer.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
package org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.webapp;
1313

1414
import java.io.IOException;
15+
import java.util.Map.Entry;
1516

1617
import org.eclipse.jdt.annotation.NonNull;
1718
import org.eclipse.tracecompass.tmf.core.model.OutputElementStyle;
@@ -38,11 +39,31 @@ public OutputElementStyleSerializer() {
3839
super(OutputElementStyle.class);
3940
}
4041

42+
/**
43+
* Serialize {@link OutputElementStyle} according to TSP, see here for details:
44+
* {@link org.eclipse.tracecompass.incubator.internal.trace.server.jersey.rest.core.model.OutputElementStyle}
45+
*/
46+
@SuppressWarnings({ "nls", "null" })
4147
@Override
4248
public void serialize(@NonNull OutputElementStyle value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
4349
gen.writeStartObject();
44-
gen.writeStringField("parentKey", value.getParentKey()); //$NON-NLS-1$
45-
gen.writeObjectField("values", value.getStyleValues()); //$NON-NLS-1$
50+
gen.writeStringField("parentKey", value.getParentKey());
51+
52+
// Verify the type of style values. Make sure only supported types are returned.
53+
gen.writeObjectFieldStart("values");
54+
for (Entry<String, Object> entry : value.getStyleValues().entrySet()) {
55+
Object entryValue = entry.getValue();
56+
if (entryValue instanceof Long longValue) {
57+
if (longValue >= Integer.MIN_VALUE && longValue <= Integer.MAX_VALUE) {
58+
gen.writeFieldName(entry.getKey());
59+
gen.writeNumber(longValue.intValue());
60+
}
61+
} else if ((entryValue instanceof String) || (entryValue instanceof Number)) {
62+
gen.writeFieldName(entry.getKey());
63+
gen.writeObject(entryValue);
64+
}
65+
}
66+
gen.writeEndObject();
4667
gen.writeEndObject();
4768
}
4869

0 commit comments

Comments
 (0)