Skip to content

Commit

Permalink
Add inner class support (#104)
Browse files Browse the repository at this point in the history
* add inner class support

* add test for InnerClass support

* fix qualifiedBuilderName generation and add test for inner class with protected fields

* add expected output source to InnerClassTest
  • Loading branch information
AndreasBoehm authored and sockeqwe committed Jul 3, 2018
1 parent c395c80 commit 36997f1
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,41 @@ public String getSimpleName() {
return classElement.getSimpleName().toString();
}

/*
* Returns the Builder name
* e.g. LoginFragmentBuilder or LoginActivity$$LoginFragment
*/
public String getBuilderName() {
String builderName = getSimpleName() + "Builder";

if(isInnerClass()) {
return classElement.getEnclosingElement().getSimpleName() + "$$" + builderName;

} else {
return builderName;
}
}

/**
* Returns the qualified Builder name
* e.g. com.hannesdorfman.package.LoginFragmentBuilder or com.hannesdorfman.package.LoginActivity$$LoginFragment
*/
public String getQualifiedBuilderName() {
String qualifiedBuilderName = getQualifiedName() + "Builder";

if(isInnerClass()) {
return qualifiedBuilderName
.replace("." + getSimpleName() + "Builder", "$$" + getSimpleName() + "Builder");

} else {
return qualifiedBuilderName;
}
}

public boolean isInnerClass() {
return classElement.getEnclosingElement().getKind() == ElementKind.CLASS;
}

public Set<ArgumentAnnotatedField> getAll() {
Set<ArgumentAnnotatedField> all = new HashSet<ArgumentAnnotatedField>(getRequiredFields());
all.addAll(getOptionalFields());
Expand Down Expand Up @@ -228,5 +263,4 @@ private boolean isSetterApplicable(ArgumentAnnotatedField field, ExecutableEleme

}


}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public class ArgProcessor extends AbstractProcessor {
private static final String CUSTOM_BUNDLER_BUNDLE_KEY =
"com.hannesdorfmann.fragmentargs.custom.bundler.2312A478rand.";

private static final Map<String, String> ARGUMENT_TYPES = new HashMap<String, String>(20);
private static final Map<String, String> ARGUMENT_TYPES =
new HashMap<String, String>(20);

/**
* Annotation Processor Option
Expand Down Expand Up @@ -569,7 +570,8 @@ public boolean process(Set<? extends TypeElement> type, RoundEnvironment env) {

AnnotatedFragment fragment = collectArgumentsForType(fragmentClass);

String builder = fragment.getSimpleName() + "Builder";
String builderName = fragment.getBuilderName();

List<Element> originating = new ArrayList<Element>(10);
originating.add(fragmentClass);
TypeMirror superClass = fragmentClass.getSuperclass();
Expand All @@ -583,7 +585,7 @@ public boolean process(Set<? extends TypeElement> type, RoundEnvironment env) {
}

String qualifiedFragmentName = fragment.getQualifiedName();
String qualifiedBuilderName = qualifiedFragmentName + "Builder";
String qualifiedBuilderName = fragment.getQualifiedBuilderName();

Element[] orig = originating.toArray(new Element[originating.size()]);
origHelper = orig;
Expand All @@ -600,14 +602,19 @@ public boolean process(Set<? extends TypeElement> type, RoundEnvironment env) {
}
}

// for inner classes we need to add an import
if(fragment.isInnerClass()) {
jw.emitImports(fragment.getQualifiedName());
}

jw.emitEmptyLine();

// Additional builder annotations
for (String builderAnnotation : additionalBuilderAnnotations) {
jw.emitAnnotation(builderAnnotation);
}

jw.beginType(builder, "class", EnumSet.of(Modifier.PUBLIC, Modifier.FINAL));
jw.beginType(builderName, "class", EnumSet.of(Modifier.PUBLIC, Modifier.FINAL));

if (!fragment.getBundlerVariableMap().isEmpty()) {
jw.emitEmptyLine();
Expand All @@ -632,7 +639,7 @@ public boolean process(Set<? extends TypeElement> type, RoundEnvironment env) {
args[index++] = annotate ? "@NonNull " + arg.getType() : arg.getType();
args[index++] = arg.getVariableName();
}
jw.beginMethod(null, builder, EnumSet.of(Modifier.PUBLIC), args);
jw.beginMethod(null, builderName, EnumSet.of(Modifier.PUBLIC), args);

for (ArgumentAnnotatedField arg : required) {
writePutArguments(jw, arg.getVariableName(), "mArguments", arg);
Expand All @@ -642,13 +649,13 @@ public boolean process(Set<? extends TypeElement> type, RoundEnvironment env) {

if (!required.isEmpty()) {
jw.emitEmptyLine();
writeNewFragmentWithRequiredMethod(builder, fragmentClass, jw, args);
writeNewFragmentWithRequiredMethod(builderName, fragmentClass, jw, args);
}

Set<ArgumentAnnotatedField> optionalArguments = fragment.getOptionalFields();

for (ArgumentAnnotatedField arg : optionalArguments) {
writeBuilderMethod(builder, jw, arg);
writeBuilderMethod(builderName, jw, arg);
}

jw.emitEmptyLine();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.hannesdorfmann.fragmentargs.processor;

import com.google.testing.compile.JavaFileObjects;

import static com.google.common.truth.Truth.assert_;
import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;

public final class CompileTest {

public static void assertClassCompilesWithoutError(final String classResourceName, final String outputClassResourceName) {
assert_().about(javaSource())
.that(JavaFileObjects.forResource(classResourceName))
.processedWith(new ArgProcessor())
.compilesWithoutError()
.and()
.generatesSources(JavaFileObjects.forResource(outputClassResourceName));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.hannesdorfmann.fragmentargs.processor;

import org.junit.Test;

import static com.hannesdorfmann.fragmentargs.processor.CompileTest.assertClassCompilesWithoutError;

public class InnerClassTest {

@Test
public void innerClass() {
assertClassCompilesWithoutError("ClassWithInnerClass.java", "ClassWithInnerClassBuilder.java");
}

@Test
public void innerClassWithProtectedField() {
assertClassCompilesWithoutError("InnerClassWithProtectedField.java", "InnerClassWithProtectedFieldBuilder.java");
}
}
16 changes: 16 additions & 0 deletions processor/src/test/resources/ClassWithInnerClass.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.hannesdorfmann.fragmentargs.processor.test;

@com.hannesdorfmann.fragmentargs.annotation.FragmentWithArgs
public class ClassWithInnerClass extends android.app.Fragment {

@com.hannesdorfmann.fragmentargs.annotation.Arg
String arg;

@com.hannesdorfmann.fragmentargs.annotation.FragmentWithArgs
public static class InnerClass extends android.app.Fragment {

@com.hannesdorfmann.fragmentargs.annotation.Arg
String arg;
}

}
39 changes: 39 additions & 0 deletions processor/src/test/resources/ClassWithInnerClassBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.hannesdorfmann.fragmentargs.processor.test;

import android.os.Bundle;

public final class ClassWithInnerClassBuilder {

private final Bundle mArguments = new Bundle();

public ClassWithInnerClassBuilder(String arg) {

mArguments.putString("arg", arg);
}

public static ClassWithInnerClass newClassWithInnerClass(String arg) {
return new ClassWithInnerClassBuilder(arg).build();
}

public Bundle buildBundle() {
return new Bundle(mArguments);
}

public static final void injectArguments(ClassWithInnerClass fragment) {
Bundle args = fragment.getArguments();
if (args == null) {
throw new IllegalStateException("No arguments set. Have you set up this Fragment with the corresponding FragmentArgs Builder? ");
}

if (!args.containsKey("arg")) {
throw new IllegalStateException("required argument arg is not set");
}
fragment.arg = args.getString("arg");
}

public ClassWithInnerClass build() {
ClassWithInnerClass fragment = new ClassWithInnerClass();
fragment.setArguments(mArguments);
return fragment;
}
}
16 changes: 16 additions & 0 deletions processor/src/test/resources/InnerClassWithProtectedField.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.hannesdorfmann.fragmentargs.processor.test;

@com.hannesdorfmann.fragmentargs.annotation.FragmentWithArgs
public class InnerClassWithProtectedField extends android.app.Fragment {

@com.hannesdorfmann.fragmentargs.annotation.Arg
protected String arg;

@com.hannesdorfmann.fragmentargs.annotation.FragmentWithArgs
public static class InnerClass extends android.app.Fragment {

@com.hannesdorfmann.fragmentargs.annotation.Arg
protected String arg;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.hannesdorfmann.fragmentargs.processor.test;

import android.os.Bundle;

public final class InnerClassWithProtectedFieldBuilder {

private final Bundle mArguments = new Bundle();

public InnerClassWithProtectedFieldBuilder(String arg) {

mArguments.putString("arg", arg);
}

public static InnerClassWithProtectedField newInnerClassWithProtectedField(String arg) {
return new InnerClassWithProtectedFieldBuilder(arg).build();
}

public Bundle buildBundle() {
return new Bundle(mArguments);
}

public static final void injectArguments(InnerClassWithProtectedField fragment) {
Bundle args = fragment.getArguments();
if (args == null) {
throw new IllegalStateException("No arguments set. Have you set up this Fragment with the corresponding FragmentArgs Builder? ");
}

if (!args.containsKey("arg")) {
throw new IllegalStateException("required argument arg is not set");
}
fragment.arg = args.getString("arg");
}

public InnerClassWithProtectedField build() {
InnerClassWithProtectedField fragment = new InnerClassWithProtectedField();
fragment.setArguments(mArguments);
return fragment;
}
}

0 comments on commit 36997f1

Please sign in to comment.