Skip to content

Commit

Permalink
Refactor third party builder discovery.
Browse files Browse the repository at this point in the history
This helps discover the builder methods which can be on
value, or builder, and discovered in multiple orders.
  • Loading branch information
daicoden committed Jul 20, 2017
1 parent fee6e74 commit fc2fdeb
Show file tree
Hide file tree
Showing 12 changed files with 529 additions and 192 deletions.
Expand Up @@ -3,6 +3,7 @@
import org.immutables.fixture.builder.attribute_builders.FirstPartyWithBuilderExtension; import org.immutables.fixture.builder.attribute_builders.FirstPartyWithBuilderExtension;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithBuilderClassCopyMethod; import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithBuilderClassCopyMethod;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithBuilderInstanceCopyMethod; import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithBuilderInstanceCopyMethod;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithNestedBuilder;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithValueClassCopyMethod; import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithValueClassCopyMethod;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithValueInstanceCopyMethod; import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithValueInstanceCopyMethod;
import org.immutables.value.Value.Immutable; import org.immutables.value.Value.Immutable;
Expand All @@ -22,4 +23,6 @@ public abstract class NeapolitanAttributeBuilderParent {
public abstract ThirdPartyImmutableWithBuilderClassCopyMethod tpiWithBuilderClassCopyMethod(); public abstract ThirdPartyImmutableWithBuilderClassCopyMethod tpiWithBuilderClassCopyMethod();


public abstract FirstPartyWithBuilderExtension fpWithBuilderExtension(); public abstract FirstPartyWithBuilderExtension fpWithBuilderExtension();

public abstract ThirdPartyImmutableWithNestedBuilder tpiWithNestedBuilder();
} }
@@ -0,0 +1,35 @@
package org.immutables.fixture.builder.attribute_builders;

public class ThirdPartyImmutableWithNestedBuilder {

private final String value;

private ThirdPartyImmutableWithNestedBuilder(String value) {
this.value = value;
}

public String getValue() {
return value;
}

public static class Builder {

private String value;

public Builder() {
}

public Builder(ThirdPartyImmutableWithNestedBuilder copy) {
this.value = copy.getValue();
}

public Builder setValue(String value) {
this.value = value;
return this;
}

public ThirdPartyImmutableWithNestedBuilder doTheBuild() {
return new ThirdPartyImmutableWithNestedBuilder(value);
}
}
}
@@ -0,0 +1,7 @@
package org.immutables.fixture.builder.detection;

import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithNestedBuilder;

public interface NestedDetection {
ThirdPartyImmutableWithNestedBuilder getThirdParty();
}
@@ -0,0 +1,12 @@
package org.immutables.fixture.builder.detection;

import org.immutables.value.Value.Immutable;
import org.immutables.value.Value.Style;

@Immutable
@Style(
attributeBuilderDetection = true,
attributeBuilder = {"*Builder", "builder", "new"}
)
public abstract class NewTokenAttributeBuilderParent implements NestedDetection{
}
@@ -0,0 +1,12 @@
package org.immutables.fixture.builder.detection;

import org.immutables.value.Value.Immutable;
import org.immutables.value.Value.Style;

@Immutable
@Style(
attributeBuilderDetection = true,
attributeBuilder = {"*Builder", "builder"}
)
public abstract class NoNewTokenAttributeBuilderParent implements NestedDetection {
}
Expand Up @@ -12,8 +12,11 @@
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutable; import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutable;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithBuilderClassCopyMethod; import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithBuilderClassCopyMethod;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithBuilderInstanceCopyMethod; import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithBuilderInstanceCopyMethod;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithNestedBuilder;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithValueClassCopyMethod; import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithValueClassCopyMethod;
import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithValueInstanceCopyMethod; import org.immutables.fixture.builder.attribute_builders.ThirdPartyImmutableWithValueInstanceCopyMethod;
import org.immutables.fixture.builder.detection.ImmutableNewTokenAttributeBuilderParent;
import org.immutables.fixture.builder.detection.ImmutableNoNewTokenAttributeBuilderParent;
import org.immutables.fixture.builder.functional.AttributeBuilderBuilderI; import org.immutables.fixture.builder.functional.AttributeBuilderBuilderI;
import org.immutables.fixture.builder.functional.AttributeBuilderValueI; import org.immutables.fixture.builder.functional.AttributeBuilderValueI;
import org.immutables.fixture.builder.functional.BuilderFunction; import org.immutables.fixture.builder.functional.BuilderFunction;
Expand Down Expand Up @@ -175,12 +178,16 @@ public void testThirdPartyApiWithValueInstanceCopy() {
FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder() FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder()
.value("first praty") .value("first praty")
.build(); .build();
ThirdPartyImmutableWithNestedBuilder tpiWithNestedBuilder = new ThirdPartyImmutableWithNestedBuilder.Builder()
.setValue("third party")
.doTheBuild();


//builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod); //builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod);
builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod); builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod);
builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod); builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod);
builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod); builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod);
builder.fpWithBuilderExtension(fpWithBuilderExtension); builder.fpWithBuilderExtension(fpWithBuilderExtension);
builder.tpiWithNestedBuilder(tpiWithNestedBuilder);


ThirdPartyImmutableWithValueInstanceCopyMethod.Builder thirdPartyBuilder = ThirdPartyImmutableWithValueInstanceCopyMethod.Builder thirdPartyBuilder =
builder.tpiWithValueInstanceCopyMethodBuilder() builder.tpiWithValueInstanceCopyMethodBuilder()
Expand Down Expand Up @@ -216,12 +223,16 @@ public void testThirdPartyApiWithValueClassCopy() {
FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder() FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder()
.value("first praty") .value("first praty")
.build(); .build();
ThirdPartyImmutableWithNestedBuilder tpiWithNestedBuilder = new ThirdPartyImmutableWithNestedBuilder.Builder()
.setValue("third party")
.doTheBuild();


builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod); builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod);
//builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod); //builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod);
builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod); builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod);
builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod); builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod);
builder.fpWithBuilderExtension(fpWithBuilderExtension); builder.fpWithBuilderExtension(fpWithBuilderExtension);
builder.tpiWithNestedBuilder(tpiWithNestedBuilder);


ThirdPartyImmutableWithValueClassCopyMethod.Builder thirdPartyBuilder = ThirdPartyImmutableWithValueClassCopyMethod.Builder thirdPartyBuilder =
builder.tpiWithValueClassCopyMethodBuilder() builder.tpiWithValueClassCopyMethodBuilder()
Expand Down Expand Up @@ -257,12 +268,16 @@ public void testThirdPartyApiWithBuilderInstanceCopy() {
FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder() FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder()
.value("first praty") .value("first praty")
.build(); .build();
ThirdPartyImmutableWithNestedBuilder tpiWithNestedBuilder = new ThirdPartyImmutableWithNestedBuilder.Builder()
.setValue("third party")
.doTheBuild();


builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod); builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod);
builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod); builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod);
//builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod); //builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod);
builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod); builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod);
builder.fpWithBuilderExtension(fpWithBuilderExtension); builder.fpWithBuilderExtension(fpWithBuilderExtension);
builder.tpiWithNestedBuilder(tpiWithNestedBuilder);


ThirdPartyImmutableWithBuilderInstanceCopyMethod.Builder thirdPartyBuilder = ThirdPartyImmutableWithBuilderInstanceCopyMethod.Builder thirdPartyBuilder =
builder.tpiWithBuilderInstanceCopyMethodBuilder() builder.tpiWithBuilderInstanceCopyMethodBuilder()
Expand Down Expand Up @@ -298,12 +313,16 @@ public void testThirdPartyApiWithBuilderClassCopy() {
FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder() FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder()
.value("first party") .value("first party")
.build(); .build();
ThirdPartyImmutableWithNestedBuilder tpiWithNestedBuilder = new ThirdPartyImmutableWithNestedBuilder.Builder()
.setValue("third party")
.doTheBuild();


builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod); builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod);
builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod); builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod);
builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod); builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod);
//builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod); //builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod);
builder.fpWithBuilderExtension(fpWithBuilderExtension); builder.fpWithBuilderExtension(fpWithBuilderExtension);
builder.tpiWithNestedBuilder(tpiWithNestedBuilder);


ThirdPartyImmutableWithBuilderClassCopyMethod.Builder thirdPartyBuilder = ThirdPartyImmutableWithBuilderClassCopyMethod.Builder thirdPartyBuilder =
builder.tpiWithBuilderClassCopyMethodBuilder() builder.tpiWithBuilderClassCopyMethodBuilder()
Expand Down Expand Up @@ -339,12 +358,16 @@ public void testFirstPartyApiWithExtendingBuilder() {
FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder() FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder()
.value("first party") .value("first party")
.build(); .build();
ThirdPartyImmutableWithNestedBuilder tpiWithNestedBuilder = new ThirdPartyImmutableWithNestedBuilder.Builder()
.setValue("third party")
.doTheBuild();


builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod); builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod);
builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod); builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod);
builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod); builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod);
builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod); builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod);
//builder.fpWithBuilderExtension(fpWithBuilderExtension); //builder.fpWithBuilderExtension(fpWithBuilderExtension);
builder.tpiWithNestedBuilder(tpiWithNestedBuilder);


FirstPartyWithBuilderExtension.Builder fpWithBuilderExtensionBuilder = FirstPartyWithBuilderExtension.Builder fpWithBuilderExtensionBuilder =
builder.fpWithBuilderExtensionBuilder() builder.fpWithBuilderExtensionBuilder()
Expand All @@ -355,4 +378,71 @@ public void testFirstPartyApiWithExtendingBuilder() {
check(copy.fpWithBuilderExtension().value()) check(copy.fpWithBuilderExtension().value())
.is("first party through attributeBuilder"); .is("first party through attributeBuilder");
} }

@Test
public void testThirdPartyApiWithNestedBuilder() {
ImmutableNeapolitanAttributeBuilderParent.Builder builder
= ImmutableNeapolitanAttributeBuilderParent.builder();

ThirdPartyImmutableWithValueInstanceCopyMethod tpiWithValueInstanceCopyMethod = ThirdPartyImmutableWithValueInstanceCopyMethod
.generateNewBuilder()
.setValue("third party")
.build();
ThirdPartyImmutableWithValueClassCopyMethod tpiWithValueClassCopyMethod = ThirdPartyImmutableWithValueClassCopyMethod
.generateNewBuilder()
.setValue("third party")
.doTheBuild();
ThirdPartyImmutableWithBuilderInstanceCopyMethod tpiWithBuilderInstanceCopyMethod = ThirdPartyImmutableWithBuilderInstanceCopyMethod
.generateNewBuilder()
.setValue("third party")
.doTheBuild();
ThirdPartyImmutableWithBuilderClassCopyMethod tpiWithBuilderClassCopyMethod = ThirdPartyImmutableWithBuilderClassCopyMethod
.generateNewBuilder()
.setValue("third party")
.doTheBuild();
FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder()
.value("first party")
.build();
ThirdPartyImmutableWithNestedBuilder tpiWithNestedBuilder = new ThirdPartyImmutableWithNestedBuilder.Builder()
.setValue("third party")
.doTheBuild();

builder.tpiWithValueInstanceCopyMethod(tpiWithValueInstanceCopyMethod);
builder.tpiWithValueClassCopyMethod(tpiWithValueClassCopyMethod);
builder.tpiWithBuilderInstanceCopyMethod(tpiWithBuilderInstanceCopyMethod);
builder.tpiWithBuilderClassCopyMethod(tpiWithBuilderClassCopyMethod);
builder.fpWithBuilderExtension(fpWithBuilderExtension);
//builder.tpiWithNestedBuilder(tpiWithNestedBuilder);

ThirdPartyImmutableWithNestedBuilder.Builder tpiWithNestedBuilderBuilder =
builder.tpiWithNestedBuilderBuilder()
.setValue("third party through attributeBuilder");

ImmutableNeapolitanAttributeBuilderParent copy = ImmutableNeapolitanAttributeBuilderParent
.copyOf(builder.build());
check(copy.tpiWithNestedBuilder().getValue())
.is("third party through attributeBuilder");
}

@Test
public void newKeywordNeededForNestedBuilder() {
boolean thrown = false;
String thirdPartyBuilder = "thirdPartyBuilder";

try {
check(ImmutableNewTokenAttributeBuilderParent.Builder.class
.getMethod(thirdPartyBuilder, null));
} catch (NoSuchMethodException e) {
check("Could not find method when it should have been generated", false);
}
try {
check(ImmutableNoNewTokenAttributeBuilderParent.Builder.class
.getMethod(thirdPartyBuilder, null));
} catch (NoSuchMethodException e) {
thrown = true;
}

check("Generated nested builder when we should not have", thrown);
}

} }
Expand Up @@ -27,7 +27,12 @@ public enum ValueToBuilderTarget {
/** /**
* Would look like {@code ValueObject.Builder builderCopy = ValueObject.Builder.from(valueInstance);} * Would look like {@code ValueObject.Builder builderCopy = ValueObject.Builder.from(valueInstance);}
*/ */
BUILDER_TYPE BUILDER_TYPE,

/**
* Would look like {@coode ValueObject.Builder builderCopy = new ValueObject.Builder(valueInstance);}
*/
BUILDER_CONSTRUCTOR
} }


public abstract ValueToBuilderTarget getValueToBuilderTarget(); public abstract ValueToBuilderTarget getValueToBuilderTarget();
Expand All @@ -41,15 +46,13 @@ public enum ValueToBuilderTarget {
protected abstract String getValueToBuilderMethod(); protected abstract String getValueToBuilderMethod();


/** /**
* Uses {@link #getValueToBuilderTarget()} ()} to determine appropriate format for * Uses {@link #getValueToBuilderTarget()} to determine appropriate format for
* creating a new builder from a value object. * creating a new builder from a value object.
* *
* The template needs to still query {@link #getValueToBuilderTarget()} ()} to determine * The template needs to still query {@link #isCopyMethodOnValueInstance()} to determine
* whether to use {@code [expression].[n.getQualifiedValueToBuilderMethod]()} vs * whether to use {@code [expression].[n.getQualifiedValueToBuilderMethod]()} vs
* {@code [n.getQualifiedValueToBuilderMethod]([expression])} * {@code [n.getQualifiedValueToBuilderMethod]([expression])}
* *
* If a template could pass an argument, then we could handle the logic in this method.
*
* @return method to use for converting a value to a builder. * @return method to use for converting a value to a builder.
*/ */
public String getQualifiedValueToBuilderMethod() { public String getQualifiedValueToBuilderMethod() {
Expand All @@ -64,6 +67,8 @@ public String getQualifiedValueToBuilderMethod() {
.format("%s().%s", getQualifiedBuilderConstructorMethod(), getValueToBuilderMethod()); .format("%s().%s", getQualifiedBuilderConstructorMethod(), getValueToBuilderMethod());
case BUILDER_TYPE: case BUILDER_TYPE:
return String.format("%s.%s", getQualifiedBuilderTypeName(), getValueToBuilderMethod()); return String.format("%s.%s", getQualifiedBuilderTypeName(), getValueToBuilderMethod());
case BUILDER_CONSTRUCTOR:
return getQualifiedBuilderConstructorMethod();
default: default:
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
String.format("Could not handle %s", getValueToBuilderTarget())); String.format("Could not handle %s", getValueToBuilderTarget()));
Expand All @@ -89,19 +94,13 @@ public boolean isCopyMethodOnValueInstance() {
/** /**
* A fully qualified type for the value object. * A fully qualified type for the value object.
* *
* If {@link Style#deepImmutablesDetection()} is {@code true}, then the qualified value
* type is the generated immutables concrete class.
*
* @return fully qualified name of the value type. * @return fully qualified name of the value type.
*/ */
public abstract String getQualifiedValueTypeName(); public abstract String getQualifiedValueTypeName();


/** /**
* A fully qualified type for the builder object. * A fully qualified type for the builder object.
* *
* If using a nested static builder, then this must return the final concrete builder
* class.
*
* @return fully qualified name of the builder type. * @return fully qualified name of the builder type.
*/ */
public abstract String getQualifiedBuilderTypeName(); public abstract String getQualifiedBuilderTypeName();
Expand All @@ -119,7 +118,7 @@ public String getQualifiedValueTypeNameWithUnderscores() {
* A fully qualified path and method which creates a new instance of a builder. * A fully qualified path and method which creates a new instance of a builder.
* *
* If the builder is constructed from a no-arg constructor, the {@code new} keyword * If the builder is constructed from a no-arg constructor, the {@code new} keyword
* is prepended with a space. * should be prepended with a space.
* *
* @return static path which invoked will create a new empty builder. No () included. * @return static path which invoked will create a new empty builder. No () included.
*/ */
Expand Down

0 comments on commit fc2fdeb

Please sign in to comment.