Skip to content

Commit 5068345

Browse files
authored
match creator aliases to fields (#445)
1 parent 1fdfa59 commit 5068345

File tree

5 files changed

+155
-6
lines changed

5 files changed

+155
-6
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package org.example.customer.creator;
2+
3+
import io.avaje.jsonb.Json;
4+
import io.avaje.jsonb.Json.Alias;
5+
import io.avaje.jsonb.Json.Creator;
6+
import io.avaje.jsonb.Json.Property;
7+
8+
@Json
9+
public class Quaternion {
10+
11+
// Scalar r in versor form
12+
@Property("W")
13+
private final double m_w;
14+
15+
// Vector v in versor form
16+
@Property("X")
17+
private final double m_x;
18+
19+
@Property("Y")
20+
private final double m_y;
21+
22+
@Property("Z")
23+
private final double m_z;
24+
25+
/** Constructs a quaternion with a default angle of 0 degrees. */
26+
public Quaternion() {
27+
m_w = 1.0;
28+
m_x = 0.0;
29+
m_y = 0.0;
30+
m_z = 0.0;
31+
}
32+
33+
/**
34+
* Constructs a quaternion with the given components.
35+
*
36+
* @param w W component of the quaternion.
37+
* @param x X component of the quaternion.
38+
* @param y Y component of the quaternion.
39+
* @param z Z component of the quaternion.
40+
*/
41+
@Creator
42+
public Quaternion(
43+
@Alias("W") double w,
44+
@Alias("X") double x,
45+
@Alias("Y") double y,
46+
@Alias("Z") double z) {
47+
m_w = w;
48+
m_x = x;
49+
m_y = y;
50+
m_z = z;
51+
}
52+
53+
/**
54+
* Returns W component of the quaternion.
55+
*
56+
* @return W component of the quaternion.
57+
*/
58+
public double getW() {
59+
return m_w;
60+
}
61+
62+
/**
63+
* Returns X component of the quaternion.
64+
*
65+
* @return X component of the quaternion.
66+
*/
67+
public double getX() {
68+
return m_x;
69+
}
70+
71+
/**
72+
* Returns Y component of the quaternion.
73+
*
74+
* @return Y component of the quaternion.
75+
*/
76+
public double getY() {
77+
return m_y;
78+
}
79+
80+
/**
81+
* Returns Z component of the quaternion.
82+
*
83+
* @return Z component of the quaternion.
84+
*/
85+
public double getZ() {
86+
return m_z;
87+
}
88+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.example.customer.creator;
2+
3+
import io.avaje.jsonb.Jsonb;
4+
import org.junit.jupiter.api.Test;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
8+
class QuaternionTest {
9+
10+
final Jsonb jsonb = Jsonb.builder().build();
11+
12+
@Test
13+
void asJson() {
14+
var q = new Quaternion(0.1, 0.2, 0.3, 0.4);
15+
16+
String json = jsonb.toJson(q);
17+
Quaternion fromJson = jsonb.type(Quaternion.class).fromJson(json);
18+
19+
assertThat(fromJson.getW()).isEqualTo(0.1);
20+
assertThat(fromJson.getX()).isEqualTo(0.2);
21+
assertThat(fromJson.getY()).isEqualTo(0.3);
22+
assertThat(fromJson.getZ()).isEqualTo(0.4);
23+
}
24+
}

jsonb-generator/src/main/java/io/avaje/jsonb/generator/ClassReader.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import javax.lang.model.element.ElementKind;
1414
import javax.lang.model.element.TypeElement;
1515

16+
import io.avaje.jsonb.generator.MethodReader.MethodParam;
17+
1618
final class ClassReader implements BeanReader {
1719

1820
private static final boolean useInstanceofPattern = jdkVersion() >= 17;
@@ -509,11 +511,13 @@ private void writeJsonBuildResult(Append writer, String varName) {
509511
writer.append(", ");
510512
}
511513

512-
final var paramName = params.get(i).name();
514+
MethodParam methodParam = params.get(i);
515+
final var paramName = methodParam.name();
516+
final var aliases = aliasesForParam(methodParam);
513517
var name =
514518
allFields.stream()
515519
.filter(FieldReader::isConstructorParam)
516-
.filter(f -> f.propertyName().equals(paramName) || f.fieldName().equals(paramName))
520+
.filter(field -> isMatchParam(field, paramName, aliases))
517521
.map(FieldReader::fieldName)
518522
.findFirst()
519523
.orElse(paramName);
@@ -534,6 +538,20 @@ private void writeJsonBuildResult(Append writer, String varName) {
534538
}
535539
}
536540

541+
private static boolean isMatchParam(FieldReader field, String paramName, Set<String> aliases) {
542+
return field.propertyName().equals(paramName)
543+
|| field.fieldName().equals(paramName)
544+
|| field.aliases().contains(paramName)
545+
|| aliases.contains(field.propertyName())
546+
|| aliases.contains(field.fieldName());
547+
}
548+
549+
private static Set<String> aliasesForParam(MethodParam methodParam) {
550+
return AliasPrism.getOptionalOn(methodParam.element()).map(AliasPrism::value).stream()
551+
.flatMap(List::stream)
552+
.collect(Collectors.toSet());
553+
}
554+
537555
private void writeFromJsonWithSubTypes(Append writer) {
538556
final var typeVar = usesTypeProperty ? "_val$" + typePropertyKey() : "type";
539557
final var useSwitch = subTypes.size() >= 3;

jsonb-generator/src/main/java/io/avaje/jsonb/generator/FieldReader.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,9 @@ void writeFromJsonSwitch(Append writer, boolean defaultConstructor, String varNa
244244
writer.append(" case \"%s\":", propertyKey).eol();
245245
}
246246
final String propertyKey = caseInsensitiveKeys ? propertyName.toLowerCase() : propertyName;
247-
writer.append(" case \"%s\": ", propertyKey).eol();
247+
if (!aliases.contains(propertyName)) {
248+
writer.append(" case \"%s\": ", propertyKey).eol();
249+
}
248250
if (!deserialize) {
249251
writer.append(" reader.skipValue();");
250252
} else {

jsonb-generator/src/main/java/io/avaje/jsonb/generator/TypeReader.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,12 @@ void read(TypeElement type) {
162162
for (var param : constructor.getParams()) {
163163
var name = param.name();
164164
var element = param.element();
165-
var matchingField = localFields.stream()
166-
.filter(f -> f.propertyName().equals(name) || f.fieldName().equals(name))
167-
.findFirst();
165+
var aliases = aliasesForParam(element);
166+
167+
var matchingField =
168+
localFields.stream()
169+
.filter(field -> isMatchParam(field, name, aliases))
170+
.findFirst();
168171
matchingField.ifPresentOrElse(f -> f.readParam(element), () -> readField(element, localFields));
169172
}
170173
}
@@ -190,6 +193,20 @@ void read(TypeElement type) {
190193
}
191194
}
192195

196+
private static boolean isMatchParam(FieldReader field, String name, Set<String> aliases) {
197+
return field.propertyName().equals(name)
198+
|| field.fieldName().equals(name)
199+
|| field.aliases().contains(name)
200+
|| aliases.contains(field.propertyName())
201+
|| aliases.contains(field.fieldName());
202+
}
203+
204+
private static Set<String> aliasesForParam(VariableElement element) {
205+
return AliasPrism.getOptionalOn(element).map(AliasPrism::value).stream()
206+
.flatMap(List::stream)
207+
.collect(Collectors.toSet());
208+
}
209+
193210
private void readField(Element element, List<FieldReader> localFields) {
194211
final Element mixInField = mixInFields.get(element.getSimpleName().toString());
195212
if (mixInField != null && APContext.types().isSameType(mixInField.asType(), element.asType())) {

0 commit comments

Comments
 (0)