Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,30 @@
</pluginManagement>

<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.flowingcode.vaadin.jsonmigration.ElementalNodeAsmPostProcessor</mainClass>
<arguments>
<argument>${project.build.outputDirectory}/com/flowingcode/vaadin/jsonmigration/ElementalArrayNode.class</argument>
<argument>${project.build.outputDirectory}/com/flowingcode/vaadin/jsonmigration/ElementalBooleanNode.class</argument>
<argument>${project.build.outputDirectory}/com/flowingcode/vaadin/jsonmigration/ElementalNullNode.class</argument>
<argument>${project.build.outputDirectory}/com/flowingcode/vaadin/jsonmigration/ElementalNumberNode.class</argument>
<argument>${project.build.outputDirectory}/com/flowingcode/vaadin/jsonmigration/ElementalObjectNode.class</argument>
<argument>${project.build.outputDirectory}/com/flowingcode/vaadin/jsonmigration/ElementalStringNode.class</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
Expand Down Expand Up @@ -216,6 +240,9 @@
<quiet>true</quiet>
<doclint>none</doclint>
<failOnWarnings>true</failOnWarnings>
<sourceFileExcludes>
<sourceFileExclude>**/ElementalNodeAsmPostProcessor.java</sourceFileExclude>
</sourceFileExcludes>
<links>
<link>https://javadoc.io/doc/com.vaadin/vaadin-platform-javadoc/${vaadin.version}</link>
</links>
Expand All @@ -229,6 +256,8 @@
<!-- Generated file that shouldn't be included in add-ons -->
<excludes>
<exclude>META-INF/VAADIN/config/flow-build-info.json</exclude>
<exclude>com/flowingcode/vaadin/jsonmigration/ElementalNodeAsmPostProcessor.class</exclude>
<exclude>com/flowingcode/vaadin/jsonmigration/ElementalNodeAsmPostProcessor$*.class</exclude>
</excludes>
</configuration>
</plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Json Migration Helper
* %%
* Copyright (C) 2025 Flowing Code
* Copyright (C) 2025 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -29,7 +29,7 @@
import tools.jackson.databind.node.JsonNodeFactory;

@SuppressWarnings("serial")
class ElementalArrayNode extends ArrayNode implements UnsupportedJsonValueImpl {
class ElementalArrayNode extends ArrayNode implements UnsupportedJsonValueImpl<JsonArray> {

public ElementalArrayNode(JsonArray a) {
super(JsonNodeFactory.instance, children(a));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Json Migration Helper
* %%
* Copyright (C) 2025 Flowing Code
* Copyright (C) 2025 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,11 +19,12 @@
*/
package com.flowingcode.vaadin.jsonmigration;

import elemental.json.JsonBoolean;
import elemental.json.JsonType;
import tools.jackson.databind.node.BooleanNode;

@SuppressWarnings("serial")
class ElementalBooleanNode extends BooleanNode implements UnsupportedJsonValueImpl {
class ElementalBooleanNode extends BooleanNode implements UnsupportedJsonValueImpl<JsonBoolean> {

public ElementalBooleanNode(boolean value) {
super(value);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*-
* #%L
* Json Migration Helper
* %%
* Copyright (C) 2025 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package com.flowingcode.vaadin.jsonmigration;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Optional;
import lombok.NonNull;
import lombok.SneakyThrows;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;

/**
* Dynamically modifies the class header to implement the JSON interface specified in the
* UnsupportedJsonValueImpl<T> generic argument.
*/
public class ElementalNodeAsmPostProcessor {

public static void main(String[] args) throws Exception {
for (String arg : args) {
Path classPath = Paths.get(arg);
byte[] b = Files.readAllBytes(classPath);

ClassReader cr = new ClassReader(b);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitorImpl transformer = new ClassVisitorImpl(cw);

cr.accept(transformer, 0);

if (transformer.modified) {
Files.write(classPath, cw.toByteArray());
System.out.println("Successfully patched: " + classPath.getFileName());
}
}
}

private static class ClassVisitorImpl extends ClassVisitor {

private final static String TARGET_INTERFACE =
Type.getInternalName(UnsupportedJsonValueImpl.class);

boolean modified;

public ClassVisitorImpl(ClassVisitor cv) {
super(Opcodes.ASM9, cv);
}

@Override
@SneakyThrows
public void visit(int version, int access, String name, String signature, String superName,
String[] interfaces) {
String detectedInterface = detectInterface(signature);

for (String intf : interfaces) {
if (intf.equals(detectedInterface)) {
return;
}
}

modified = true;
interfaces = Arrays.copyOf(interfaces, interfaces.length + 1);
interfaces[interfaces.length - 1] = detectedInterface;
super.visit(version, access, name, signature, superName, interfaces);
}

private String detectInterface(@NonNull String signature) {
// Extracts the internal name of the specific generic type argument 'T' from
// the class signature implementing UnsupportedJsonValueImpl<T>.
String[] detectedInterface = new String[1];
SignatureReader reader = new SignatureReader(signature);
reader.accept(new SignatureVisitor(Opcodes.ASM9) {
private boolean insideTargetInterface = false;

@Override
public SignatureVisitor visitTypeArgument(char wildcard) {
// Move into the <T> block
return super.visitTypeArgument(wildcard);
}

@Override
public SignatureVisitor visitInterface() {
return this;
}

@Override
public void visitClassType(String name) {
if (name.equals(TARGET_INTERFACE)) {
insideTargetInterface = true;
} else if (insideTargetInterface && detectedInterface[0] == null) {
// This is the first class type found AFTER UnsupportedJsonValueImpl
// which represents the generic argument T
detectedInterface[0] = name;
insideTargetInterface = false; // Stop looking
}
}

@Override
public void visitEnd() {
insideTargetInterface = false;
super.visitEnd();
}

});
return Optional.ofNullable(detectedInterface[0])
.orElseThrow(() -> new IllegalArgumentException("Failed to extract interface"));
}

@Override
public void visitEnd() {
super.visitEnd();
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Json Migration Helper
* %%
* Copyright (C) 2025 Flowing Code
* Copyright (C) 2025 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,11 +19,12 @@
*/
package com.flowingcode.vaadin.jsonmigration;

import elemental.json.JsonNull;
import elemental.json.JsonType;
import tools.jackson.databind.node.NullNode;

@SuppressWarnings("serial")
class ElementalNullNode extends NullNode implements UnsupportedJsonValueImpl {
class ElementalNullNode extends NullNode implements UnsupportedJsonValueImpl<JsonNull> {

public ElementalNullNode() {
super();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Json Migration Helper
* %%
* Copyright (C) 2025 Flowing Code
* Copyright (C) 2025 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,11 +19,12 @@
*/
package com.flowingcode.vaadin.jsonmigration;

import elemental.json.JsonNumber;
import elemental.json.JsonType;
import tools.jackson.databind.node.DoubleNode;

@SuppressWarnings("serial")
class ElementalNumberNode extends DoubleNode implements UnsupportedJsonValueImpl {
class ElementalNumberNode extends DoubleNode implements UnsupportedJsonValueImpl<JsonNumber> {

public ElementalNumberNode(double value) {
super(value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Json Migration Helper
* %%
* Copyright (C) 2025 Flowing Code
* Copyright (C) 2025 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,7 +31,7 @@
import tools.jackson.databind.node.ObjectNode;

@SuppressWarnings("serial")
class ElementalObjectNode extends ObjectNode implements UnsupportedJsonValueImpl {
class ElementalObjectNode extends ObjectNode implements UnsupportedJsonValueImpl<JsonObject> {

public ElementalObjectNode(JsonObject o) {
super(JsonNodeFactory.instance, children(o));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Json Migration Helper
* %%
* Copyright (C) 2025 Flowing Code
* Copyright (C) 2025 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,11 +19,12 @@
*/
package com.flowingcode.vaadin.jsonmigration;

import elemental.json.JsonString;
import elemental.json.JsonType;
import tools.jackson.databind.node.StringNode;

@SuppressWarnings("serial")
class ElementalStringNode extends StringNode implements UnsupportedJsonValueImpl {
class ElementalStringNode extends StringNode implements UnsupportedJsonValueImpl<JsonString> {

public ElementalStringNode(String value) {
super(value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Json Migration Helper
* %%
* Copyright (C) 2025 Flowing Code
* Copyright (C) 2025 - 2026 Flowing Code
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,7 +22,7 @@
import elemental.json.JsonValue;
import tools.jackson.databind.JsonNode;

interface UnsupportedJsonValueImpl extends JsonValue {
interface UnsupportedJsonValueImpl<T extends JsonValue> extends JsonValue {

@Override
default boolean asBoolean() {
Expand Down
Loading