Skip to content
This repository has been archived by the owner on Oct 10, 2024. It is now read-only.

Construct transparent objects #968

Open
robertvazan opened this issue May 21, 2023 · 3 comments · May be fixed by #999
Open

Construct transparent objects #968

robertvazan opened this issue May 21, 2023 · 3 comments · May be fixed by #999

Comments

@robertvazan
Copy link

It would be neat to have CodeBlock API that recursively emits code to construct transparent values (records, arrays, collections, enums, primitives, strings, and null, perhaps others).

For now, I have a utility method that does this for the types I care about:

public class JavaPoetEx {
    public static CodeBlock construct(Object object) {
        if (object == null)
            return CodeBlock.of("null");
        if (object instanceof Integer || object instanceof Long || object instanceof Double || object instanceof Float)
            return CodeBlock.of("$L", object);
        if (object instanceof Enum<?> en)
            return CodeBlock.of("$T.$N", en.getClass(), en.name());
        if (object instanceof Record record) {
            return CodeBlock.of("new $T($L)", record.getClass(), StreamEx.of(record.getClass().getDeclaredFields())
                .filter(f -> !Modifier.isStatic(f.getModifiers()))
                .map(Exceptions.sneak().function(f -> record.getClass().getMethod(f.getName()).invoke(record)))
                .map(JavaPoetEx::construct)
                .collect(CodeBlock.joining(", ")));
        }
        throw new IllegalArgumentException();
    }
}

This could be implemented as a new parameter type (perhaps $V for value) that generalizes $L and $S. It would sort of serialize values as Java code the same way JSON serializes values as JavaScript code.

@l3002
Copy link

l3002 commented Jan 14, 2024

Hey @robertvazan, Would like to contribute to this issue? Could you please assign this issue to me?

And just to confirm you are looking for an API which would call a generalized method and outputs the certain result based on the type parameter, right?

@Christopher-Chianelli
Copy link

FWIW, I implemented something extremely similar to this for in-lining static final fields of a complex Object: https://github.com/Christopher-Chianelli/timefold-solver/blob/38c98a8b6311ac1ecc7fafccc35db748f7080db8/spring-integration/spring-boot-autoconfigure/src/main/java/ai/timefold/solver/spring/boot/autoconfigure/util/PojoInliner.java

In theory, it could be modified to work with any CodeBuilder as a new formatting option, something like "$O" for object or "$P" for POJO.
What I needed the feature for was in-lining a calculated complex object (i.e. many different fields and nested classes).
The main issue for integrating are:

  1. It expects the CodeBlock.Builder to be valid (i.e. cannot use it in an incomplete fragement).
  2. It needs fresh variable names to store the objects.

@Christopher-Chianelli
Copy link

Managed to make it work with fragments: #999
It still need fresh variable names to store objects; it currently uses a $$javapoet$ as a default prefix, and allows it to be changed using useNamePrefix.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants