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.ThirdPartyImmutableWithBuilderClassCopyMethod;
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.ThirdPartyImmutableWithValueInstanceCopyMethod;
import org.immutables.value.Value.Immutable;
Expand All @@ -22,4 +23,6 @@ public abstract class NeapolitanAttributeBuilderParent {
public abstract ThirdPartyImmutableWithBuilderClassCopyMethod tpiWithBuilderClassCopyMethod();

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.ThirdPartyImmutableWithBuilderClassCopyMethod;
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.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.AttributeBuilderValueI;
import org.immutables.fixture.builder.functional.BuilderFunction;
Expand Down Expand Up @@ -175,12 +178,16 @@ public void testThirdPartyApiWithValueInstanceCopy() {
FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder()
.value("first praty")
.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);

ThirdPartyImmutableWithValueInstanceCopyMethod.Builder thirdPartyBuilder =
builder.tpiWithValueInstanceCopyMethodBuilder()
Expand Down Expand Up @@ -216,12 +223,16 @@ public void testThirdPartyApiWithValueClassCopy() {
FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder()
.value("first praty")
.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);

ThirdPartyImmutableWithValueClassCopyMethod.Builder thirdPartyBuilder =
builder.tpiWithValueClassCopyMethodBuilder()
Expand Down Expand Up @@ -257,12 +268,16 @@ public void testThirdPartyApiWithBuilderInstanceCopy() {
FirstPartyWithBuilderExtension fpWithBuilderExtension = new FirstPartyWithBuilderExtension.Builder()
.value("first praty")
.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);

ThirdPartyImmutableWithBuilderInstanceCopyMethod.Builder thirdPartyBuilder =
builder.tpiWithBuilderInstanceCopyMethodBuilder()
Expand Down Expand Up @@ -298,12 +313,16 @@ public void testThirdPartyApiWithBuilderClassCopy() {
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);

ThirdPartyImmutableWithBuilderClassCopyMethod.Builder thirdPartyBuilder =
builder.tpiWithBuilderClassCopyMethodBuilder()
Expand Down Expand Up @@ -339,12 +358,16 @@ public void testFirstPartyApiWithExtendingBuilder() {
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);

FirstPartyWithBuilderExtension.Builder fpWithBuilderExtensionBuilder =
builder.fpWithBuilderExtensionBuilder()
Expand All @@ -355,4 +378,71 @@ public void testFirstPartyApiWithExtendingBuilder() {
check(copy.fpWithBuilderExtension().value())
.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);}
*/
BUILDER_TYPE
BUILDER_TYPE,

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

public abstract ValueToBuilderTarget getValueToBuilderTarget();
Expand All @@ -41,15 +46,13 @@ public enum ValueToBuilderTarget {
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.
*
* 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
* {@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.
*/
public String getQualifiedValueToBuilderMethod() {
Expand All @@ -64,6 +67,8 @@ public String getQualifiedValueToBuilderMethod() {
.format("%s().%s", getQualifiedBuilderConstructorMethod(), getValueToBuilderMethod());
case BUILDER_TYPE:
return String.format("%s.%s", getQualifiedBuilderTypeName(), getValueToBuilderMethod());
case BUILDER_CONSTRUCTOR:
return getQualifiedBuilderConstructorMethod();
default:
throw new UnsupportedOperationException(
String.format("Could not handle %s", getValueToBuilderTarget()));
Expand All @@ -89,19 +94,13 @@ public boolean isCopyMethodOnValueInstance() {
/**
* 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.
*/
public abstract String getQualifiedValueTypeName();

/**
* 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.
*/
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.
*
* 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.
*/
Expand Down

0 comments on commit fc2fdeb

Please sign in to comment.