Skip to content

Commit cd3f9bf

Browse files
author
Matt Hayes
committed
Support for embedding Pig scripts in Java test files
Uses a neat trick presented by Adrian Walker in this blog post: http://www.adrianwalker.org/2011/12/java-multiline-string.html With this the pig scripts can be embedded directly in the Java files as javadoc comments on class fields. Tests are much easier to work with this way. I removed all pig test files for the util tests to demonstrate. Also added an ant target "eclipse" which generates some eclipse files. It figures out what the paths should be based on the environment. This fixes an issue where paths would be incorrect when working in another repo.
1 parent f0ad8d2 commit cd3f9bf

28 files changed

+388
-121
lines changed

.classpath .classpath.template

+9-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@
55
<classpathentry kind="src" path="test/pig"/>
66
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
77
<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
8-
<classpathentry kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=datafu&amp;ivyXmlPath=ivy.xml&amp;confs=*"/>
9-
<classpathentry kind="lib" path="otherlibs/pigunit-0.9.jar"/>
10-
<classpathentry kind="output" path="dist/testclasses"/>
8+
<classpathentry kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=@PROJECT@&amp;ivyXmlPath=ivy.xml&amp;confs=*"/>
9+
<classpathentry kind="src" path=".apt_generated">
10+
<attributes>
11+
<attribute name="optional" value="true"/>
12+
</attributes>
13+
</classpathentry>
14+
<classpathentry kind="lib" path="annotation-plugin.jar"/>
15+
<classpathentry kind="lib" path="staticlibs/pigunit-0.9.jar"/>
16+
<classpathentry kind="output" path="build/testclasses"/>
1117
</classpath>

.factorypath.template

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<factorypath>
2+
<factorypathentry kind="WKSPJAR" id="@HOME@/annotation-plugin.jar" enabled="true" runInBatchMode="false"/>
3+
</factorypath>

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
dist/
2+
build/
3+
annotation-plugin.jar
4+
.factorypath
5+
.classpath
26
docs/
37
input
48
lib/
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
eclipse.preferences.version=1
2+
org.eclipse.jdt.apt.aptEnabled=true
3+
org.eclipse.jdt.apt.genSrcDir=.apt_generated
4+
org.eclipse.jdt.apt.reconcileEnabled=true

.settings/org.eclipse.jdt.core.prefs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
eclipse.preferences.version=1
2+
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3+
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
4+
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5+
org.eclipse.jdt.core.compiler.compliance=1.6
6+
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7+
org.eclipse.jdt.core.compiler.debug.localVariable=generate
8+
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9+
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10+
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11+
org.eclipse.jdt.core.compiler.processAnnotations=enabled
12+
org.eclipse.jdt.core.compiler.source=1.6

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ Or [download](https://github.com/linkedin/datafu/archive/master.zip) the code.
151151

152152
Here are some common tasks when working with the source code.
153153

154+
### Eclipse
155+
156+
To generate eclipse files:
157+
158+
ant eclipse
159+
154160
### Build the JAR
155161

156162
ant jar

build.xml

+57-2
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@
2020
<!-- directories -->
2121
<property name="src.dir" value="${basedir}/src" />
2222
<property name="java.dir" value="${src.dir}/java" />
23+
<property name="plugin.java.dir" value="${basedir}/plugin/java" />
2324
<property name="test.dir" value="${basedir}/test" />
2425
<property name="unittestsrc.dir" value="${test.dir}/unit" />
2526
<property name="pigtestsrc.dir" value="${test.dir}/pig" />
2627
<property name="dist.dir" value="${basedir}/dist" />
2728
<property name="tools.dir" value="${basedir}/tools" />
2829
<property name="lib.dir" value="${basedir}/lib" />
30+
<property name="static.lib.dir" value="${basedir}/staticlibs" />
2931
<property name="classes.dir" value="${dist.dir}/classes" />
32+
<property name="plugin.classes.dir" value="${dist.dir}/pluginclasses" />
3033
<property name="report.dir" value="${basedir}/report" />
3134
<property name="report.unit.dir" value="${report.dir}/unit" />
3235
<property name="report.pig.dir" value="${report.dir}/pig" />
@@ -59,12 +62,37 @@
5962
<property name="maven.jar" location="${ivy.jar.dir}/maven-ant-tasks-${maven.jar.version}.jar"/>
6063

6164
<loadproperties srcfile="${ivy.jar.dir}/libraries.properties"/>
65+
66+
<basename property="basedirname" file="${basedir}"/>
6267

6368
<target name="all" depends="clean, jar, sources-jar, javadoc-jar, coverage" description="Build all artifacts." />
6469

6570
<target name="init" depends="ivy-resolve">
6671
<mkdir dir="${dist.dir}" />
6772
</target>
73+
74+
<target name="eclipse" depends="jar,jar-plugin">
75+
<delete file="${basedir}/.factorypath"/>
76+
<copy file="${basedir}/.factorypath.template"
77+
tofile="${basedir}/.factorypath">
78+
<filterchain>
79+
<replacetokens>
80+
<token key="HOME" value="/${basedirname}"/>
81+
</replacetokens>
82+
</filterchain>
83+
</copy>
84+
<echo message="Created .factorypath"/>
85+
<delete file="${basedir}/.classpath"/>
86+
<copy file="${basedir}/.classpath.template"
87+
tofile="${basedir}/.classpath">
88+
<filterchain>
89+
<replacetokens>
90+
<token key="PROJECT" value="${basedirname}"/>
91+
</replacetokens>
92+
</filterchain>
93+
</copy>
94+
<echo message="Created .classpath"/>
95+
</target>
6896

6997
<target name="maven-ant-tasks-jar-download" description="Download maven tasks jar">
7098
<mkdir dir="${ivy.jar.dir}"/>
@@ -119,11 +147,17 @@
119147

120148
<taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
121149

150+
<path id="plugin-classpath">
151+
<fileset dir="${static.lib.dir}">
152+
<include name="*.jar" />
153+
</fileset>
154+
</path>
155+
122156
<path id="base-test-classpath">
123157
<fileset dir="${lib.dir}">
124158
<include name="*.jar" />
125159
</fileset>
126-
<fileset dir="${basedir}/otherlibs">
160+
<fileset dir="${static.lib.dir}">
127161
<include name="*.jar" />
128162
</fileset>
129163
<pathelement path="${classes.dir}" />
@@ -137,6 +171,7 @@
137171
<fileset dir="${dist.dir}">
138172
<include name="*.jar" />
139173
</fileset>
174+
<pathelement path="${plugin.classes.dir}" />
140175
</path>
141176

142177
<path id="instrumented-test-classpath">
@@ -157,6 +192,7 @@
157192
</macrodef>
158193

159194
<target name="clean" description="Delete generated files.">
195+
<delete dir="${basedir}/build" />
160196
<delete dir="${lib.dir}" />
161197
<delete dir="${dist.dir}" />
162198
<delete dir="${docs.dir}" />
@@ -175,6 +211,24 @@
175211
<classpath refid="main-classpath" />
176212
</javac>
177213
</target>
214+
215+
<target name="build-plugins" depends="init" description="Compile main source tree java files">
216+
<replace-dir dir="${plugin.classes.dir}" />
217+
<javac destdir="${plugin.classes.dir}" target="1.5" debug="true" deprecation="false" failonerror="true" includeantruntime="false">
218+
<src path="${plugin.java.dir}" />
219+
<classpath refid="plugin-classpath" />
220+
</javac>
221+
</target>
222+
223+
<target name="jar-plugin" depends="build-plugins" description="Builds the plugin JAR">
224+
<delete file="${basedir}/annotation-plugin.jar" />
225+
<jar destfile="${basedir}/annotation-plugin.jar">
226+
<fileset dir="${plugin.classes.dir}">
227+
<include name="**/*.*" />
228+
</fileset>
229+
<service type="javax.annotation.processing.Processor" provider="org.adrianwalker.multilinestring.MultilineProcessor"/>
230+
</jar>
231+
</target>
178232

179233
<target name="build-unit-tests" depends="build" description="Compile unit test classes">
180234
<replace-dir dir="${unittestclasses.dir}" />
@@ -184,7 +238,7 @@
184238
</javac>
185239
</target>
186240

187-
<target name="build-pig-tests" depends="build, build-unit-tests" description="Compile pig test classes">
241+
<target name="build-pig-tests" depends="build,build-unit-tests,build-plugins" description="Compile pig test classes">
188242
<replace-dir dir="${pigtestclasses.dir}" />
189243
<copy todir="${pigtestclasses.dir}">
190244
<fileset dir="${pigtestsrc.dir}">
@@ -193,6 +247,7 @@
193247
</copy>
194248
<javac destdir="${pigtestclasses.dir}" target="1.5" debug="true" deprecation="false" failonerror="true" includeantruntime="false">
195249
<src path="${pigtestsrc.dir}" />
250+
<compilerarg line="-processor org.adrianwalker.multilinestring.MultilineProcessor"/>
196251
<classpath refid="test-classpath" />
197252
</javac>
198253
</target>
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.adrianwalker.multilinestring;
2+
3+
import java.util.Set;
4+
5+
import javax.annotation.processing.AbstractProcessor;
6+
import javax.annotation.processing.ProcessingEnvironment;
7+
import javax.annotation.processing.RoundEnvironment;
8+
import javax.annotation.processing.SupportedAnnotationTypes;
9+
import javax.annotation.processing.SupportedSourceVersion;
10+
import javax.lang.model.SourceVersion;
11+
import javax.lang.model.element.Element;
12+
import javax.lang.model.element.TypeElement;
13+
import javax.lang.model.util.Elements;
14+
15+
import org.eclipse.jdt.internal.compiler.apt.model.VariableElementImpl;
16+
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
17+
import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
18+
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
19+
20+
import java.lang.reflect.Constructor;
21+
22+
@SupportedAnnotationTypes({"org.adrianwalker.multilinestring.Multiline"})
23+
@SupportedSourceVersion(SourceVersion.RELEASE_6)
24+
public final class EcjMultilineProcessor extends AbstractProcessor {
25+
26+
private Elements elementUtils;
27+
28+
@Override
29+
public void init(final ProcessingEnvironment procEnv) {
30+
super.init(procEnv);
31+
this.elementUtils = procEnv.getElementUtils();
32+
}
33+
34+
@Override
35+
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
36+
Set<? extends Element> fields = roundEnv.getElementsAnnotatedWith(Multiline.class);
37+
38+
for (Element field : fields) {
39+
String docComment = elementUtils.getDocComment(field);
40+
41+
if (null != docComment) {
42+
VariableElementImpl fieldElem = (VariableElementImpl) field;
43+
FieldBinding biding = (FieldBinding) fieldElem._binding;
44+
FieldDeclaration decl = biding.sourceField();
45+
StringLiteral string = new StringLiteral(docComment.toCharArray(), decl.sourceStart, decl.sourceEnd, decl.sourceStart);
46+
decl.initialization = string;
47+
}
48+
}
49+
return true;
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.adrianwalker.multilinestring;
2+
3+
import java.util.Set;
4+
5+
import javax.annotation.processing.AbstractProcessor;
6+
import javax.annotation.processing.ProcessingEnvironment;
7+
import javax.annotation.processing.RoundEnvironment;
8+
import javax.annotation.processing.SupportedAnnotationTypes;
9+
import javax.annotation.processing.SupportedSourceVersion;
10+
import javax.lang.model.SourceVersion;
11+
import javax.lang.model.element.Element;
12+
import javax.lang.model.element.TypeElement;
13+
14+
import com.sun.tools.javac.model.JavacElements;
15+
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
16+
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
17+
import com.sun.tools.javac.tree.TreeMaker;
18+
19+
@SupportedAnnotationTypes({"org.adrianwalker.multilinestring.Multiline"})
20+
@SupportedSourceVersion(SourceVersion.RELEASE_6)
21+
public final class JavacMultilineProcessor extends AbstractProcessor {
22+
23+
private JavacElements elementUtils;
24+
private TreeMaker maker;
25+
26+
@Override
27+
public void init(final ProcessingEnvironment procEnv) {
28+
super.init(procEnv);
29+
JavacProcessingEnvironment javacProcessingEnv = (JavacProcessingEnvironment) procEnv;
30+
this.elementUtils = javacProcessingEnv.getElementUtils();
31+
this.maker = TreeMaker.instance(javacProcessingEnv.getContext());
32+
}
33+
34+
@Override
35+
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
36+
Set<? extends Element> fields = roundEnv.getElementsAnnotatedWith(Multiline.class);
37+
for (Element field : fields) {
38+
String docComment = elementUtils.getDocComment(field);
39+
if (null != docComment) {
40+
JCVariableDecl fieldNode = (JCVariableDecl) elementUtils.getTree(field);
41+
fieldNode.init = maker.Literal(docComment);
42+
}
43+
}
44+
return true;
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.adrianwalker.multilinestring;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Target({ElementType.FIELD,ElementType.LOCAL_VARIABLE})
9+
@Retention(RetentionPolicy.SOURCE)
10+
public @interface Multiline {
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.adrianwalker.multilinestring;
2+
3+
import java.util.Set;
4+
5+
import javax.annotation.processing.AbstractProcessor;
6+
import javax.annotation.processing.ProcessingEnvironment;
7+
import javax.annotation.processing.Processor;
8+
import javax.annotation.processing.RoundEnvironment;
9+
import javax.annotation.processing.SupportedAnnotationTypes;
10+
import javax.annotation.processing.SupportedSourceVersion;
11+
import javax.lang.model.SourceVersion;
12+
import javax.lang.model.element.TypeElement;
13+
14+
@SupportedAnnotationTypes({"org.adrianwalker.multilinestring.Multiline"})
15+
@SupportedSourceVersion(SourceVersion.RELEASE_6)
16+
public final class MultilineProcessor extends AbstractProcessor {
17+
private Processor delegator = null;
18+
19+
@Override
20+
public void init(final ProcessingEnvironment procEnv) {
21+
super.init(procEnv);
22+
String envClassName = procEnv.getClass().getName();
23+
if (envClassName.contains("com.sun.tools")) {
24+
delegator = new JavacMultilineProcessor();
25+
} else {
26+
delegator = new EcjMultilineProcessor();
27+
}
28+
delegator.init(procEnv);
29+
}
30+
31+
@Override
32+
public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {
33+
if (delegator == null ) {
34+
return true;
35+
}
36+
return delegator.process(annotations, roundEnv);
37+
}
38+
}
Binary file not shown.
Binary file not shown.
File renamed without changes.

test/pig/datafu/test/pig/PigTests.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ protected List<String> getDefaultArgsAsList()
5656
return argsList;
5757
}
5858

59-
protected PigTest createPigTest(String scriptPath, String... args) throws IOException
59+
protected PigTest createPigTestFromString(String str, String... args) throws IOException
60+
{
61+
return createPigTest(str.split("\n"),args);
62+
}
63+
64+
protected PigTest createPigTest(String[] lines, String... args) throws IOException
6065
{
6166
// append args to list of default args
6267
List<String> theArgs = getDefaultArgsAsList();
@@ -65,8 +70,6 @@ protected PigTest createPigTest(String scriptPath, String... args) throws IOExce
6570
theArgs.add(arg);
6671
}
6772

68-
String[] lines = getLinesFromFile(scriptPath);
69-
7073
for (String arg : theArgs)
7174
{
7275
String[] parts = arg.split("=",2);
@@ -82,9 +85,9 @@ protected PigTest createPigTest(String scriptPath, String... args) throws IOExce
8285
return new PigTest(lines);
8386
}
8487

85-
protected PigTest createPigTest(String scriptPath) throws IOException
88+
protected PigTest createPigTest(String scriptPath, String... args) throws IOException
8689
{
87-
return createPigTest(scriptPath, getDefaultArgs());
90+
return createPigTest(getLinesFromFile(scriptPath), args);
8891
}
8992

9093
protected String getJarPath()

0 commit comments

Comments
 (0)