Skip to content

Commit de3d8fc

Browse files
feat(QTDI-2215):deserialize a json to a Schema instance (#1145)
* fix(QTDI-2215): Add schema/Entry pojo. (#1146) --------- Co-authored-by: yyin-talend <yueyan.yin@qlik.com> ypiel <ypiel@talend.com>
1 parent 6bfd991 commit de3d8fc

6 files changed

Lines changed: 1291 additions & 3 deletions

File tree

component-server-parent/component-server-model/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,4 @@
7676
</plugin>
7777
</plugins>
7878
</build>
79-
</project>
79+
</project>
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* Copyright (C) 2006-2025 Talend Inc. - www.talend.com
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.talend.sdk.component.server.front.model;
17+
18+
import java.beans.ConstructorProperties;
19+
import java.util.LinkedHashMap;
20+
import java.util.Map;
21+
22+
import lombok.Data;
23+
24+
@Data
25+
public final class Entry {
26+
27+
private final String name;
28+
29+
private final String rawName;
30+
31+
private final Schema.Type type;
32+
33+
private final boolean nullable;
34+
35+
private final boolean metadata;
36+
37+
private final boolean errorCapable;
38+
39+
private final boolean valid;
40+
41+
private final Schema elementSchema;
42+
43+
private final String comment;
44+
45+
private final Map<String, String> props = new LinkedHashMap<>(0);
46+
47+
private final Object defaultValue;
48+
49+
@ConstructorProperties({ "name", "rawName", "type", "nullable", "metadata", "errorCapable",
50+
"valid", "elementSchema", "comment", "props", "defaultValue" })
51+
// Checkstyle off to let have 11 parameters to this constructor (normally 10 max)
52+
// CHECKSTYLE:OFF
53+
public Entry(
54+
final String name,
55+
final String rawName,
56+
final Schema.Type type,
57+
final boolean nullable,
58+
final boolean metadata,
59+
final boolean errorCapable,
60+
final boolean valid,
61+
final Schema elementSchema,
62+
final String comment,
63+
final Map<String, String> props,
64+
final Object defaultValue) {
65+
// CHECKSTYLE:ON
66+
this.name = name;
67+
this.rawName = rawName;
68+
this.type = type;
69+
this.nullable = nullable;
70+
this.metadata = metadata;
71+
this.errorCapable = errorCapable;
72+
this.valid = valid;
73+
this.elementSchema = elementSchema;
74+
this.comment = comment;
75+
if (props != null) {
76+
this.props.putAll(props);
77+
}
78+
this.defaultValue = defaultValue;
79+
}
80+
81+
private Object getInternalDefaultValue() {
82+
return defaultValue;
83+
}
84+
85+
@SuppressWarnings("unchecked")
86+
public <T> T getDefaultValue() {
87+
if (defaultValue == null) {
88+
return null;
89+
}
90+
91+
return switch (this.getType()) {
92+
case INT -> (T) ((Integer) ((Number) this.getInternalDefaultValue()).intValue());
93+
case LONG -> (T) ((Long) ((Number) this.getInternalDefaultValue()).longValue());
94+
case FLOAT -> (T) ((Float) ((Number) this.getInternalDefaultValue()).floatValue());
95+
case DOUBLE -> (T) ((Double) ((Number) this.getInternalDefaultValue()).doubleValue());
96+
default -> (T) this.getInternalDefaultValue();
97+
};
98+
99+
}
100+
101+
/**
102+
* * Returns the property value associated with the given key.
103+
* * @param key the property key
104+
* * @return the property value, or {@code null} if there is no mapping for the given key
105+
*/
106+
public String getOriginalFieldName() {
107+
return rawName != null ? rawName : name;
108+
}
109+
110+
public String getProp(final String key) {
111+
return this.props.get(key);
112+
}
113+
114+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* Copyright (C) 2006-2025 Talend Inc. - www.talend.com
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.talend.sdk.component.server.front.model;
17+
18+
import java.beans.ConstructorProperties;
19+
import java.math.BigDecimal;
20+
import java.time.temporal.Temporal;
21+
import java.util.Collection;
22+
import java.util.Date;
23+
import java.util.List;
24+
import java.util.Map;
25+
26+
import lombok.Data;
27+
28+
@Data
29+
public final class Schema {
30+
31+
private final Type type;
32+
33+
private final Schema elementSchema;
34+
35+
private final List<Entry> entries;
36+
37+
private final List<Entry> metadata;
38+
39+
private final Map<String, String> props;
40+
41+
@ConstructorProperties({ "type", "elementSchema", "entries", "metadata", "props" })
42+
public Schema(
43+
final Type type,
44+
final Schema elementSchema,
45+
final List<Entry> entries,
46+
final List<Entry> metadata,
47+
final Map<String, String> props) {
48+
this.type = type;
49+
this.elementSchema = elementSchema;
50+
this.entries = entries;
51+
this.metadata = metadata;
52+
this.props = props;
53+
}
54+
55+
public String getProp(final String key) {
56+
return this.props.get(key);
57+
}
58+
59+
public enum Type {
60+
61+
RECORD(new Class<?>[] { Record.class }),
62+
ARRAY(new Class<?>[] { Collection.class }),
63+
STRING(new Class<?>[] { String.class, Object.class }),
64+
BYTES(new Class<?>[] { byte[].class, Byte[].class }),
65+
INT(new Class<?>[] { Integer.class }),
66+
LONG(new Class<?>[] { Long.class }),
67+
FLOAT(new Class<?>[] { Float.class }),
68+
DOUBLE(new Class<?>[] { Double.class }),
69+
BOOLEAN(new Class<?>[] { Boolean.class }),
70+
DATETIME(new Class<?>[] { Long.class, Date.class, Temporal.class }),
71+
DECIMAL(new Class<?>[] { BigDecimal.class });
72+
73+
/**
74+
* All compatibles Java classes
75+
*/
76+
private final Class<?>[] classes;
77+
78+
Type(final Class<?>[] classes) {
79+
this.classes = classes;
80+
}
81+
82+
}
83+
}

component-server-parent/component-server/pom.xml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,6 @@
197197
<version>${project.version}</version>
198198
<scope>test</scope>
199199
</dependency>
200-
201200
</dependencies>
202201

203202
<build>
@@ -493,4 +492,4 @@
493492
</build>
494493
</profile>
495494
</profiles>
496-
</project>
495+
</project>
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/**
2+
* Copyright (C) 2006-2025 Talend Inc. - www.talend.com
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.talend.sdk.component.server.front;
17+
18+
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
import static org.junit.jupiter.api.Assertions.assertFalse;
20+
import static org.junit.jupiter.api.Assertions.assertNull;
21+
import static org.junit.jupiter.api.Assertions.assertTrue;
22+
23+
import java.util.LinkedHashMap;
24+
import java.util.Map;
25+
26+
import javax.json.bind.Jsonb;
27+
import javax.json.bind.JsonbBuilder;
28+
29+
import com.fasterxml.jackson.databind.ObjectMapper;
30+
31+
import org.junit.jupiter.api.Test;
32+
import org.talend.sdk.component.api.record.SchemaProperty;
33+
import org.talend.sdk.component.api.record.SchemaProperty.LogicalType;
34+
import org.talend.sdk.component.runtime.record.RecordBuilderFactoryImpl;
35+
import org.talend.sdk.component.server.front.model.Entry;
36+
import org.talend.sdk.component.server.front.model.Schema;
37+
38+
/**
39+
* Unit tests for {@link Entry}.
40+
*/
41+
class EntryTest {
42+
43+
private Entry createValidEntry() {
44+
Map<String, String> props = new LinkedHashMap<>(0);
45+
props.put("p1", "v1");
46+
return new Entry("name", "raw", Schema.Type.STRING, true, false, true,
47+
true, null, "comment", props, "default");
48+
}
49+
50+
private Entry createEmptyEntry() {
51+
Map<String, String> props = new LinkedHashMap<>(0);
52+
props.put("p1", "v1");
53+
return new Entry("name", null, Schema.Type.STRING, true, false, true,
54+
true, null, null, props, null);
55+
}
56+
57+
// ----------------------------------------------------------------------
58+
// Builder
59+
// ----------------------------------------------------------------------
60+
61+
@Test
62+
void builderCreatesValidEntry() {
63+
Entry entry = createValidEntry();
64+
65+
assertEquals("name", entry.getName());
66+
assertEquals("raw", entry.getRawName());
67+
assertEquals("raw", entry.getOriginalFieldName());
68+
assertEquals(Schema.Type.STRING, entry.getType());
69+
assertTrue(entry.isNullable());
70+
assertFalse(entry.isMetadata());
71+
assertTrue(entry.isErrorCapable());
72+
assertTrue(entry.isValid());
73+
assertEquals("comment", entry.getComment());
74+
assertEquals("default", entry.getDefaultValue());
75+
assertEquals("v1", entry.getProps().get("p1"));
76+
}
77+
78+
// ----------------------------------------------------------------------
79+
// Accessors
80+
// ----------------------------------------------------------------------
81+
82+
@Test
83+
void getDefaultValueIsTyped() {
84+
Entry entry = createValidEntry();
85+
86+
String value = entry.getDefaultValue();
87+
assertEquals("default", value);
88+
}
89+
90+
@Test
91+
void getDefaultValueEmpty() {
92+
Entry entry = createEmptyEntry();
93+
94+
String value = entry.getDefaultValue();
95+
assertNull(value);
96+
}
97+
98+
@Test
99+
void getPropReturnsProperty() {
100+
Entry entry = createValidEntry();
101+
assertEquals("v1", entry.getProp("p1"));
102+
assertNull(entry.getProp("k1"));
103+
}
104+
105+
// ----------------------------------------------------------------------
106+
// JSON deserialization
107+
// ----------------------------------------------------------------------
108+
109+
@Test
110+
void deserializeEntryFromJson() throws Exception {
111+
RecordBuilderFactoryImpl factory = new RecordBuilderFactoryImpl("test");
112+
org.talend.sdk.component.api.record.Schema.Entry entryImpl = factory.newEntryBuilder()
113+
.withName("éèfield")
114+
.withLogicalType(LogicalType.UUID)
115+
.withNullable(false)
116+
.withMetadata(false)
117+
.withErrorCapable(false)
118+
.withComment("test comment")
119+
.withProps(Map.of("p1", "v1"))
120+
.withDefaultValue("defaultValue")
121+
.build();
122+
123+
try (Jsonb jsonb = JsonbBuilder.create()) {
124+
String json = jsonb.toJson(entryImpl);
125+
126+
ObjectMapper mapper = new ObjectMapper();
127+
Entry entry = mapper.readValue(json, Entry.class);
128+
129+
assertEquals("_field", entry.getName());
130+
assertEquals("éèfield", entry.getRawName());
131+
assertEquals("éèfield", entry.getOriginalFieldName());
132+
assertEquals(Schema.Type.STRING, entry.getType());
133+
assertEquals(LogicalType.UUID.key(), entry.getProp(SchemaProperty.LOGICAL_TYPE));
134+
135+
assertFalse(entry.isNullable());
136+
assertFalse(entry.isMetadata());
137+
assertFalse(entry.isErrorCapable());
138+
assertTrue(entry.isValid());
139+
140+
assertEquals("test comment", entry.getComment());
141+
assertEquals("v1", entry.getProps().get("p1"));
142+
assertEquals("defaultValue", entry.getDefaultValue());
143+
}
144+
}
145+
146+
}

0 commit comments

Comments
 (0)