Playing the generator game

A while back I wrote a post on

图片[1]-Playing the generator game - 拾光赋-拾光赋

How I misunderstood Lombok

Satyarth Agrahari ・ Nov 13 ’20

#java #programming

So This time around, I didn’t wanted to make the same mistake, which brings us back to this post.

Let’s start with a simple exercise for people familiar with lombok and dependency injection. What do you think should be the generated code from the following block

@RequiredArgsConstructor(onConstructor = @__(@Inject))
public class Test {
    @NonNull @Named("testString") private final String testString;
}

Enter fullscreen mode Exit fullscreen mode

I think most people would guess (who have seen generated code by lombok) that this would translate to

public class Test {
    @Generated
    @Inject
    Test(@NonNull @Named("testString") String testString) {
        if (testString == null) {
            throw new NullPointerException("testString is marked non-null but is null");
        } else {
            this.testString = testString;   
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

But if it would have been the case, then we wouldn’t be here, would we…
So lets see what it actually generates

public class Test {
    @Generated
    @Inject
    Test(@NonNull String testString) {
        if (testString == null) {
            throw new NullPointerException("testString is marked non-null but is null");
        } else {
            this.testString = testString;   
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

But that’s strange, I can clearly see that I have annotated my field with @Named, and so how would it even find the correct dependency to inject, if it will not have the name discovery during dependency injection.

Well as it turns out, lombok doesn’t respects all annotations, since it gets too complicated to implement that behaviour. You can go through the github issues for details 1 2

So now that we know that this is the case, the question is how to resolve this.

  1. in newer versions of lombok one could add lombok.copyableAnnotations += com.google.inject.name.Named in lombok.config file and lombok would try and copy them when it generates the constructor.
  2. Go with our old fashioned constructor based injection and write
public class Test {
    @Inject
    Test(@NonNull @Named("testString") final String testString) {
        this.testString = testString;
    }
}

Enter fullscreen mode Exit fullscreen mode

I prefer 2, because of couple of reasons

  1. Putting a conf in lombok.config that determines what gets copied hides too much information and is frankly just an accident waiting to happen, when someone see this code sample and tries to copy it and it somehow works because there was no collision.
  2. It only copies the annotation which have copyable implemented for them, so in case we come across something that is not copyable, we are back to implementing 2 anyways.
  3. I like the 2nd one since its more expressive, and I like writing codes that are more expressive since eventually we are writing them for humans, and its better if we do not hide too many things and keep things simple so that the person reading code can focus more on business logic rather than spending time understanding why or why not their injection works.

原文链接:Playing the generator game

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容