Lombok: Feature Request: @Patcher -- generate a TPatcher and "Patch<T>" class

Created on 30 Nov 2018  路  5Comments  路  Source: projectlombok/lombok

I have recently started using Lombok (and I am also quite new to Java) so apologies if there is already a way to achieve what I have in mind. If so, I would greatly appreciate suggestions on how to do it.

I would like to be able to implement the PATCH verb for a REST controller.

This would look like:

PATCH /api/foos/{id}

And will contain only the changes to a Foo object in the request body.

Suppose Foo looks like the following:

{
    id: 1,
    name: "Fizz Buzz",
    state: "STARTED"
}

Then, I want to be able to call PATCH /api/foos/1 with the following request body:

{
    state: "COMPLETED"
}

I would like there to be an annotation called @Patcher available in Lombok, such that the Foo class might look like:

@Builder
@Patcher
public class Foo {
    @NotNull
    private int id;

    @NotNull
    private String name;

    @NotNull
    private FooState state;
}

Having the @Patcher annotation applied to a class should generate a class called FooPatcher which would enable the following syntax:

Patch<Foo> patch = Foo.patcher()
    .state(FooState.COMPLETED)
    .patch();

And

@PatchMapping("{id}")
public Foo patch(@PathVariable int id, @RequestBody Patch<Foo> patch) {
    Foo foo = fooService.get(id);

    // NOTE : patch.isXyzChanged() should return true only if
    // FooPatcher.xyz(newXyz) was called before FooPatcher.patch() was called
    // FooPatcher.patch() should return a Patch<Foo> object

    if (patch.isNameChanged()) {
        // TODO : implementation here
    }

    if (patch.isStateChanged()) {
        // TODO : implementation here
    }

    // TODO : implementation here

    return foo;
}

Most helpful comment

Yes, I did realize that Eclipse has it's own implementation as well, although the reasons are a bit unclear to me.

Eclipse has its own Java compiler, and Lombok is manipulating the abstract syntax tree (AST) generated by the compiler - thus each compiler has it's own version/type of AST - that's the reason.

All 5 comments

Having the @Patcher annotation applied to a class should generate a class called FooPatcher

This sentence shows that this is not the job for Lombok. Lombok manipulates existing files and does not create new ones; standard annotation processors do. Luckily, writing an AP is orders of magnitude simpler than extending Lombok.

You could also use reflection, which is even simpler. It's ugly as it's a manual step and it requires the code to compile before it can be processed, but that's what I'm using a lot currently and it works pretty well.

Infact, AFAIK applying @Builder works in a similar manner.

BTW, I am not suggesting that any new files be generated, but that 2 types be generated, similar to how the Builder class is generated by the use of the @Builder annotation.

Please see the code around the following line of code.

https://github.com/rzwitserloot/lombok/blob/4126bc277286279c38fa2df785b56eae88b606af/src/core/lombok/javac/handlers/HandleBuilder.java#L113

OK, I see that you want the generated Patcher to be an inner class just like the Builder. You've looked into the source code and don't you think that it's damn complicated? The Lombok's way(*) is only usable for the very most important features, which are also simple enough, so that they can be implemented in a way satisfying the majority of users (while patching seems to have many possible options).

I really don't think, your Patcher crosses the bar, but I'm not in charge of this project. I'm just saying that it looks rather complicated. It's also not perfectly clear to me, what it should exactly do. For this, something like "With Lombok" and "Vanilla Java" would be needed.


(*) The Lombok's way is necessary for enhancing existing code on-the-fly and is much more complicated than using AP or reflection. Recently, I wrote a code generator for comparing my entities field-by-field, generating and applying a "binary patch", and some other features. All in all some 400 lines of trivial code, half as much as the class you linked (note that there's an eclipse implementation, too).

I have no doubt that it is complicated, as indeed most of what's been done in Lombok is. In fact, to handle this properly, another class which implements Converter<S, T> would also be needed. Yes, I did realize that Eclipse has it's own implementation as well, although the reasons are a bit unclear to me.

I am not sure whether other people would be interested in a @Patcher annotation, which will allow only changes to an object to be captured by an object. That's why I raised this feature request to see if it generates any interest! :)

Thank you for engaging with me, and taking the time to respond. I really appreciate it.

Yes, I did realize that Eclipse has it's own implementation as well, although the reasons are a bit unclear to me.

Eclipse has its own Java compiler, and Lombok is manipulating the abstract syntax tree (AST) generated by the compiler - thus each compiler has it's own version/type of AST - that's the reason.

Was this page helpful?
0 / 5 - 0 ratings