Lombok: [BUG] Jxpath not working with @Accessors(chain=true)

Created on 22 Feb 2019  路  5Comments  路  Source: projectlombok/lombok

Describe the bug

The modified signature of the setXyz methods, not returning void, seems to break the bean-property-lookup methods of Jxpath. The setter method is not found by Jxpath anymore, thus setValue(...) does not work anymore.

The bug could be fixed by providing a withXyz(...)-method instead.

To Reproduce

package bug;

import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.commons.jxpath.JXPathContext;
import org.junit.Test;

import static org.junit.Assert.*;

public class JxpathTest {

  @Data
  @Accessors(chain = true) // <<< comment this in out out to see difference
  public static class Stuff {
    String string;
  }

  @Test
  public void setValuePureJxPath() {
    // arrange
    Stuff stuff = new Stuff();
    stuff.setString("old");
    JXPathContext instance = JXPathContext.newContext(stuff);
    // act
    instance.setValue("string", "value");
    // assert
    assertEquals("value", stuff.getString());
  }
}

With @Accessors(chain = true) the test fails. Commenting it out it passes.

Expected behavior

The test should pass with @Accessors(chain = true).

Version info (please complete the following information):

  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.0</version>
    <scope>provided</scope>
  </dependency>

IntelliJ, unittest run in IDE.

IntelliJ IDEA 2018.3.4 (Ultimate Edition)
Build #IU-183.5429.30, built on January 29, 2019
JRE: 1.8.0_152-release-1343-b26 amd64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
Linux 4.15.0-45-generic

Additional

I don't think this is fixable in Lombok without any changes to how @Accessors work (this could only be fixed in Jxpath, if at all, because that relies on bean property specification, I think).

My suggestion would be: Instead of modifying the signature of the Setter methods it would be better to add a method like Type withXyz(Type newValue);. Luckily @Accessors is marked experimental...

Most helpful comment

Chaining makes the setter non-compliant to the bean spec, so jxpath is actually doing the right thing.

Furthermore, withXyz() is colliding with @Wither, so that probably won't happen.

Disclaimer: I'm not a Lombok maintainer, just a contributer.

All 5 comments

Chaining makes the setter non-compliant to the bean spec, so jxpath is actually doing the right thing.

Furthermore, withXyz() is colliding with @Wither, so that probably won't happen.

Disclaimer: I'm not a Lombok maintainer, just a contributer.

this could only be fixed in Jxpath, if at all, because that relies on bean property specification, I think

I'd bet, it does, but I could imagine a chain option dealing with this.

My suggestion would be: Instead of modifying the signature of the Setter methods it would be better to _add_ a method like Type withXyz(Type newValue);.

Are you proposing to generate two (differently named) setters? I'm afraid, this would be far worse than anything else and that's what the project owners thinks, too (there was such a posting recently).

My suggestion would be: Instead of modifying the signature of the Setter methods it would be better to _add_ a method like Type withXyz(Type newValue);.

Are you proposing to generate two (differently named) setters? I'm afraid, this would be far worse than anything else and that's what the project owners thinks, too (there was such a posting recently).

I guess I did. But agree completely with your/owners assessment. Such an interface would be bad.

Good that you pointed that out, though, because I use it all the time with jaxws. I use fluent interface generation for my @XmlElements to do this:

MyType m = new MyType()
    .withMyStuff(new MyStuff()
        .withMyThing("thing")
        .withMyBar(17))
    .withMyVar(Vars.ONE));

...and now realize that having void setMyStuff(MyStuff) and MyType withMyStuff(MyStuff) is not a good interface.

But fluent interfaces are really convenient. They circumvent Javas lack of named/optional parameters. But the bean spec is in the way. Hrm...

How about an auto generated builder class then? That offers all the with-methods but no setters? Is that convenient and a good interface? I didn't try out the existing @Builder yet, but I will. I have the feeling it may offer what I want.

Note: I wasn't aware of @Wither, but creating clones all the time is not what I mean with "convenient".

How about an auto generated builder class then?

There are @lombok.Builder and .SuperBuilder (where the latter can deal with class hierarchies). I'd say, both have issues, but both are pretty good.

That offers all the with-methods but no setters?

They offer chained fluent setters (no prefix).

Is that convenient and a good interface?

In general, yes, in your case, you'll see.

Note: I wasn't aware of @Wither, but creating clones all the time is not what I mean with "convenient".

Right, @Wither is perfect when you want to modify a single field, it's on par with @Builder for two and loses for more.

Note that all these annotations are primarily meant for constructing immutable instances.

I feel the pain but unfortunately all ways to solve this problem suck more than letting it be, as others have commented on. Unfortunately, have to close it.

Was this page helpful?
0 / 5 - 0 ratings