From 06c26a7d43402b8bbfd8e2ec10d3efbe69909a48 Mon Sep 17 00:00:00 2001 From: Julien Viet Date: Fri, 15 Sep 2023 15:37:57 +0200 Subject: [PATCH] The dataobject json generator hardcodes the list of case it can support. When it resolves a case that is not supported, it simply throws an exception. We should support loading of external cases. --- .../json/generator/DataObjectJsonGen.java | 15 +---- .../codegen/converter/DataObjectTest.java | 16 +++++ .../ExternalCaseFormattedDataObject.java | 61 +++++++++++++++++++ .../java/io/vertx/codegen/format/Case.java | 39 ++++++++++++ .../io/vertx/test/codegen/format/FooCase.java | 21 +++++++ 5 files changed, 138 insertions(+), 14 deletions(-) create mode 100644 vertx-codegen-json/src/test/java/io/vertx/test/codegen/converter/ExternalCaseFormattedDataObject.java create mode 100644 vertx-codegen-processor/src/test/java/io/vertx/test/codegen/format/FooCase.java diff --git a/vertx-codegen-json/src/main/java/io/vertx/codegen/json/generator/DataObjectJsonGen.java b/vertx-codegen-json/src/main/java/io/vertx/codegen/json/generator/DataObjectJsonGen.java index 0cd8826f3..c5dfa7913 100644 --- a/vertx-codegen-json/src/main/java/io/vertx/codegen/json/generator/DataObjectJsonGen.java +++ b/vertx-codegen-json/src/main/java/io/vertx/codegen/json/generator/DataObjectJsonGen.java @@ -377,19 +377,6 @@ private Case getCase(DataObjectModel model) { .stream().filter(ann -> ann.getName().equals(DataObject.class.getName())) .findFirst().get(); ClassTypeInfo cti = (ClassTypeInfo) abc.getMember("jsonPropertyNameFormatter"); - switch (cti.getName()) { - case "io.vertx.codegen.format.CamelCase": - return CamelCase.INSTANCE; - case "io.vertx.codegen.format.SnakeCase": - return SnakeCase.INSTANCE; - case "io.vertx.codegen.format.LowerCamelCase": - return LowerCamelCase.INSTANCE; - case "io.vertx.codegen.format.KebabCase": - return KebabCase.INSTANCE; - case "io.vertx.codegen.format.QualifiedCase": - return QualifiedCase.INSTANCE; - default: - throw new UnsupportedOperationException("Todo"); - } + return Case.loadCase(cti.getName()); } } diff --git a/vertx-codegen-json/src/test/java/io/vertx/test/codegen/converter/DataObjectTest.java b/vertx-codegen-json/src/test/java/io/vertx/test/codegen/converter/DataObjectTest.java index a78656559..bc0f9cb7c 100644 --- a/vertx-codegen-json/src/test/java/io/vertx/test/codegen/converter/DataObjectTest.java +++ b/vertx-codegen-json/src/test/java/io/vertx/test/codegen/converter/DataObjectTest.java @@ -849,6 +849,22 @@ public void testSnakeFormatted() { Assert.assertEquals(expected, test); } + @Test + public void testExternallyFormatted() { + ExternalCaseFormattedDataObject obj = new ExternalCaseFormattedDataObject(); + JsonObject expected = new JsonObject() + .put("foo", "val1") + .put("foofooBar", "val2") + .put("foofooBarfooJuu", "val3"); + ExternalCaseFormattedDataObjectConverter.fromJson(expected, obj); + Assert.assertEquals("val1", obj.getFoo()); + Assert.assertEquals("val2", obj.getFooBar()); + Assert.assertEquals("val3", obj.getFooBarJuu()); + JsonObject test = new JsonObject(); + ExternalCaseFormattedDataObjectConverter.toJson(obj, test); + Assert.assertEquals(expected, test); + } + @Test public void testBase64Basic() { TestDataObjectBase64Basic obj = new TestDataObjectBase64Basic(); diff --git a/vertx-codegen-json/src/test/java/io/vertx/test/codegen/converter/ExternalCaseFormattedDataObject.java b/vertx-codegen-json/src/test/java/io/vertx/test/codegen/converter/ExternalCaseFormattedDataObject.java new file mode 100644 index 000000000..85433f2aa --- /dev/null +++ b/vertx-codegen-json/src/test/java/io/vertx/test/codegen/converter/ExternalCaseFormattedDataObject.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2017 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + */ + +package io.vertx.test.codegen.converter; + +import io.vertx.codegen.annotations.DataObject; +import io.vertx.codegen.format.SnakeCase; +import io.vertx.core.json.JsonObject; +import io.vertx.test.codegen.format.FooCase; + +/** + * @author Julien Viet + */ +@DataObject(generateConverter = true, jsonPropertyNameFormatter = FooCase.class) +public class ExternalCaseFormattedDataObject { + + private String foo; + private String fooBar; + private String fooBarJuu; + + public ExternalCaseFormattedDataObject() { + } + + public ExternalCaseFormattedDataObject(JsonObject json) { + } + + public String getFoo() { + return foo; + } + + public ExternalCaseFormattedDataObject setFoo(String foo) { + this.foo = foo; + return this; + } + + public String getFooBar() { + return fooBar; + } + + public ExternalCaseFormattedDataObject setFooBar(String fooBar) { + this.fooBar = fooBar; + return this; + } + + public String getFooBarJuu() { + return fooBarJuu; + } + + public ExternalCaseFormattedDataObject setFooBarJuu(String fooBarJuu) { + this.fooBarJuu = fooBarJuu; + return this; + } +} diff --git a/vertx-codegen-processor/src/main/java/io/vertx/codegen/format/Case.java b/vertx-codegen-processor/src/main/java/io/vertx/codegen/format/Case.java index 5db323974..bccaa227e 100644 --- a/vertx-codegen-processor/src/main/java/io/vertx/codegen/format/Case.java +++ b/vertx-codegen-processor/src/main/java/io/vertx/codegen/format/Case.java @@ -5,12 +5,51 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** * @author Julien Viet */ public abstract class Case { + private static Case ERROR = new io.vertx.codegen.format.Case() {}; + + private static final ConcurrentMap CACHED_CASES = new ConcurrentHashMap<>(); + + /** + * Resolve a case given its Java FQN. + * + * @param name the case FQN + * @return the loaded case, {@code null} on errors + */ + public static Case loadCase(String name) { + Case found = CACHED_CASES.computeIfAbsent(name, n -> { + // Maybe use java util service loading mechanism + switch (name) { + case "io.vertx.codegen.format.CamelCase": + return CamelCase.INSTANCE; + case "io.vertx.codegen.format.SnakeCase": + return SnakeCase.INSTANCE; + case "io.vertx.codegen.format.LowerCamelCase": + return LowerCamelCase.INSTANCE; + case "io.vertx.codegen.format.KebabCase": + return KebabCase.INSTANCE; + case "io.vertx.codegen.format.QualifiedCase": + return QualifiedCase.INSTANCE; + default: + try { + Class clazz = Case.class.getClassLoader().loadClass(name); + Case i = (Case) clazz.getConstructor().newInstance(); + return i; + } catch (Exception e) { + return ERROR; + } + } + }); + return found == ERROR ? null : found; + } + public String name() { throw new UnsupportedOperationException(); } diff --git a/vertx-codegen-processor/src/test/java/io/vertx/test/codegen/format/FooCase.java b/vertx-codegen-processor/src/test/java/io/vertx/test/codegen/format/FooCase.java new file mode 100644 index 000000000..02a75a379 --- /dev/null +++ b/vertx-codegen-processor/src/test/java/io/vertx/test/codegen/format/FooCase.java @@ -0,0 +1,21 @@ +package io.vertx.test.codegen.format; + +import io.vertx.codegen.format.Case; + +import java.util.ArrayList; +import java.util.List; + +/** + * Chain everything with foo + */ +public class FooCase extends Case { + + @Override + public String format(Iterable atoms) { + List names = new ArrayList<>(); + for (String s : atoms) { + names.add(s); + } + return String.join("foo", names); + } +}