Skip to content

Commit ccacc43

Browse files
committed
refactor: finalize deserializer interfaces and cleanup docs
1 parent 0f2f1d5 commit ccacc43

File tree

28 files changed

+170
-209
lines changed

28 files changed

+170
-209
lines changed

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,27 +93,27 @@ public class AppConfig {
9393
```java
9494
import org.msuo.config2java.*;
9595

96-
AppConfig luaCfg = LuaDeserializer.deserialize(
96+
AppConfig luaCfg = new LuaDeserializer().deserialize(
9797
"return { name = 'svc', port = 9090, mode = 'PROD' }",
9898
AppConfig.class
9999
);
100100

101-
AppConfig groovyCfg = GroovyDeserializer.deserialize(
101+
AppConfig groovyCfg = new GroovyDeserializer().deserialize(
102102
"return [name: 'svc', port: 9090, mode: 'PROD']",
103103
AppConfig.class
104104
);
105105

106-
AppConfig tomlCfg = TomlDeserializer.deserialize(
106+
AppConfig tomlCfg = new TomlDeserializer().deserialize(
107107
"name = 'svc'\nport = 9090\nmode = 'PROD'",
108108
AppConfig.class
109109
);
110110

111-
AppConfig jsonCfg = JsonDeserializer.deserialize(
111+
AppConfig jsonCfg = new JsonDeserializer().deserialize(
112112
"{\"name\":\"svc\",\"port\":9090,\"mode\":\"PROD\"}",
113113
AppConfig.class
114114
);
115115

116-
AppConfig xmlCfg = XmlDeserializer.deserialize(
116+
AppConfig xmlCfg = new XmlDeserializer().deserialize(
117117
"<config><name>svc</name><port>9090</port><mode>PROD</mode></config>",
118118
AppConfig.class
119119
);
@@ -126,7 +126,7 @@ The exception message also includes a tree view of failing paths.
126126

127127
```java
128128
try {
129-
JsonDeserializer.deserialize("{\"port\":0}", AppConfig.class);
129+
new JsonDeserializer().deserialize("{\"port\":0}", AppConfig.class);
130130
} catch (ConfigDeserializationException ex) {
131131
ex.forEachError((segments, error) ->
132132
System.out.println(segments + " -> " + error.getErrorType().getClass().getSimpleName())
@@ -142,7 +142,7 @@ Parse/eval failures are separate and throw `ConfigSourceException`.
142142

143143
```java
144144
try {
145-
TomlDeserializer.deserialize("name = ", AppConfig.class);
145+
new TomlDeserializer().deserialize("name = ", AppConfig.class);
146146
} catch (ConfigSourceException ex) {
147147
System.out.println(ex.phase()); // parse or evaluate
148148
System.out.println(ex.format()); // TOML / JSON / XML / Lua / Groovy

errors.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Example:
2020

2121
```java
2222
try {
23-
JsonDeserializer.deserialize(source, MyCfg.class);
23+
new JsonDeserializer().deserialize(source, MyCfg.class);
2424
} catch (ConfigDeserializationException ex) {
2525
ex.forEachError((segments, error) -> {
2626
System.out.println(segments);
@@ -131,7 +131,7 @@ Handling errors via API:
131131

132132
```java
133133
try {
134-
JsonDeserializer.deserialize(source, ShowcaseCfg.class);
134+
new JsonDeserializer().deserialize(source, ShowcaseCfg.class);
135135
} catch (ConfigDeserializationException ex) {
136136
// Stable assertions should use API values, not message-string matching.
137137
ex.forEachError((segments, error) ->

modules/deserializer/README.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ implementation "org.msuo:deserializer:<version>"
2929

3030
## For language implementers
3131

32+
`Deserializer` defines the required API:
33+
34+
- implement `deserialize(String source, Class<T> configClass)`
35+
- reuse default file overloads from the interface (`Path` / `File`)
36+
37+
Script formats can implement `ScriptDeserializer`, which adds:
38+
39+
- `deserialize(String, Class<T>, Map<String, String> env, Map<String, ?> globals)`
40+
- default no-injection `deserialize(String, Class<T>)`
41+
42+
`AbstractScriptDeserializer` provides shared env/global normalization and delegates format-specific parsing through `parse(...)`.
43+
3244
A language module typically:
3345

3446
1. Parses source text into native objects.
@@ -37,9 +49,6 @@ A language module typically:
3749

3850
The core mapper then handles the rest.
3951

40-
`Deserializer` defines the required `deserialize(CharSequence, Class<T>)` contract and provides default file/path overloads.
41-
`ScriptInputNormalizer` provides shared helpers for script-backed modules (Lua, Groovy) to normalize injected environment/global maps.
42-
4352
## Error model
4453

4554
`ConfigDeserializationException` exposes:
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.msuo.config2java;
2+
3+
import java.util.Collections;
4+
import java.util.LinkedHashMap;
5+
import java.util.Map;
6+
7+
public abstract class AbstractScriptDeserializer implements ScriptDeserializer {
8+
9+
@Override
10+
public final <T> T deserialize(
11+
String source,
12+
Class<T> configClass,
13+
Map<String, String> environment,
14+
Map<String, ?> globals
15+
) {
16+
return ObjectMapper.deserialize(
17+
parse(
18+
source,
19+
normalizeEnvironment(environment),
20+
normalizeGlobals(globals)
21+
),
22+
configClass
23+
);
24+
}
25+
26+
protected abstract ConfigValue parse(
27+
String source,
28+
Map<String, String> environment,
29+
Map<String, Object> globals
30+
);
31+
32+
private static Map<String, String> normalizeEnvironment(
33+
Map<String, String> environment
34+
) {
35+
return environment == null
36+
? Collections.emptyMap()
37+
: Collections.unmodifiableMap(new LinkedHashMap<>(environment));
38+
}
39+
40+
private static Map<String, Object> normalizeGlobals(Map<String, ?> globals) {
41+
return globals == null
42+
? Collections.emptyMap()
43+
: Collections.unmodifiableMap(new LinkedHashMap<>(globals));
44+
}
45+
}

modules/deserializer/src/main/java/org/msuo/config2java/ConfigDeserializationException.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@ public PathNode getErrorPathTree() {
3333

3434
@Override
3535
public String getMessage() {
36-
return buildMessage(PathTreeFormatter.format(getErrorPathTree()));
37-
}
38-
39-
private static String buildMessage(String pathTree) {
40-
return "Config deserialization failed:\n" + pathTree;
36+
return "Config deserialization failed:\n" + PathTreeFormatter.format(getErrorPathTree());
4137
}
4238

4339
public static final class PathNode {

modules/deserializer/src/main/java/org/msuo/config2java/Deserializer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99

1010
public interface Deserializer {
1111

12-
<T> T deserialize(CharSequence source, Class<T> configClass);
12+
<T> T deserialize(String source, Class<T> configClass);
1313

1414
default <T> T deserialize(Path file, Charset charset, Class<T> configClass)
1515
throws IOException {
16-
return deserialize((CharSequence) Files.readString(file, charset), configClass);
16+
return deserialize(Files.readString(file, charset), configClass);
1717
}
1818

1919
default <T> T deserialize(Path file, Class<T> configClass)

modules/deserializer/src/main/java/org/msuo/config2java/ErrorCollector.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,16 @@ private static List<String> toPathSegments(Path path) {
4343
Path.Segment[] segments = path.segments();
4444
List<String> out = new ArrayList<>(Math.max(0, segments.length - 1));
4545
for (int i = 1; i < segments.length; i++) {
46-
out.add(PathTextFormatter.label(segments[i]));
46+
out.add(toPathLabel(segments[i]));
4747
}
4848
return out;
4949
}
50+
51+
private static String toPathLabel(Path.Segment segment) {
52+
if (segment.kind == Path.SegmentKind.ROOT) return "$";
53+
if (segment.kind == Path.SegmentKind.FIELD) return String.valueOf(segment.value);
54+
if (segment.kind == Path.SegmentKind.INDEX) return "[" + String.valueOf(segment.value) + "]";
55+
if (segment.kind == Path.SegmentKind.MAP_KEY) return "[" + String.valueOf(segment.value) + "]";
56+
return "{" + String.valueOf(segment.value) + "}";
57+
}
5058
}

modules/deserializer/src/main/java/org/msuo/config2java/PathTextFormatter.java

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.msuo.config2java;
2+
3+
import java.util.Collections;
4+
import java.util.Map;
5+
6+
public interface ScriptDeserializer extends Deserializer {
7+
8+
<T> T deserialize(
9+
String source,
10+
Class<T> configClass,
11+
Map<String, String> environment,
12+
Map<String, ?> globals
13+
);
14+
15+
@Override
16+
default <T> T deserialize(String source, Class<T> configClass) {
17+
return deserialize(
18+
source,
19+
configClass,
20+
Collections.emptyMap(),
21+
Collections.emptyMap()
22+
);
23+
}
24+
}

modules/deserializer/src/main/java/org/msuo/config2java/ScriptInputNormalizer.java

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)