Skip to content

Commit b26900f

Browse files
authored
Fix remaining spotbugs and checkstyle complaints and enable PR blocking (#137)
* Fix remaining spotbugs issues and enable PR blocking * Remaining checkstyle complaints * Fixes after rebasing
1 parent 5e2e244 commit b26900f

File tree

71 files changed

+404
-342
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+404
-342
lines changed

build.gradle

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
plugins {
2-
id("com.github.spotbugs") version "6.0.26"
2+
id("com.github.spotbugs") version "6.1.10"
33
}
44

55
subprojects {
66
apply plugin: 'checkstyle'
77
apply plugin: 'com.github.spotbugs'
88

9-
tasks.withType(JavaCompile) {
10-
options.release = 8
9+
tasks.withType(JavaCompile).configureEach {
10+
options.release = 11
1111
options.compilerArgs << '-Xlint:deprecation'
1212
options.compilerArgs << '-Xlint:unchecked'
1313
}
14-
tasks.withType(Javadoc) {
14+
tasks.withType(Javadoc).configureEach {
1515
options.addStringOption('Xdoclint:none', '-quiet')
1616
}
1717

1818
spotbugs {
19-
ignoreFailures = true
19+
ignoreFailures = false
2020
showProgress = true
21-
reportsDir = file("$buildDir/spotbugs")
21+
reportsDir = file("$rootProject.layout.buildDirectory/spotbugs")
2222
includeFilter = file("$rootDir/config/spotbugs/include.xml")
2323
excludeFilter = file("$rootDir/config/spotbugs/exclude.xml")
2424
}

config/checkstyle/checkstyle.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
LinkedIn Java style.
99
-->
1010
<module name="Checker">
11-
<property name="severity" value="warning"/>
11+
<property name="severity" value="error"/>
1212
<property name="fileExtensions" value="java"/>
1313

1414
<module name="TreeWalker">

config/spotbugs/exclude.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,21 @@
77
<Match>
88
<Class name="~.*models.*"/>
99
</Match>
10+
11+
<!--
12+
Allow a class to hold or return mutable objects. While this has obvious risks, it is much too
13+
common a pattern to treat as a bug.
14+
-->
15+
<Match>
16+
<Bug code="EI, EI2"/>
17+
</Match>
18+
19+
<!--
20+
Allow CT_CONSTRUCTOR_THROW in PipelineRules. The constructor pattern used by Calcite makes this
21+
unavoidable for new rules.
22+
-->
23+
<Match>
24+
<Class name="~.*PipelineRules.*"/>
25+
<Bug code="CT"/>
26+
</Match>
1027
</FindBugsFilter>

hoptimator-api/src/main/java/com/linkedin/hoptimator/Source.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import java.util.List;
44
import java.util.Map;
5-
import java.util.stream.Collectors;
6-
75

86
public class Source implements Deployable {
97

hoptimator-api/src/main/java/com/linkedin/hoptimator/Validator.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ static void validateSubdomainName(String s, Issues issues) {
2727
}
2828

2929
static <T, U> void validateUnique(Collection<T> collection, Function<T, U> accessor, Issues issues) {
30-
Set<U> keys = new HashSet<U>();
30+
Set<U> keys = new HashSet<>();
3131
for (T t : collection) {
3232
U u = accessor.apply(t);
3333
if (keys.contains(u)) {
@@ -149,17 +149,13 @@ private String format(int indentLevel) {
149149
return "";
150150
}
151151
StringBuilder sb = new StringBuilder();
152-
for (int i = 0; i < indentLevel; i++) {
153-
sb.append(" ");
154-
}
152+
sb.append(" ".repeat(Math.max(0, indentLevel)));
155153
if (context != null && !context.isEmpty()) {
156154
sb.append(context);
157155
sb.append(":\n");
158156
}
159157
for (String s : issues) {
160-
for (int i = 0; i < indentLevel; i++) {
161-
sb.append(" ");
162-
}
158+
sb.append(" ".repeat(Math.max(0, indentLevel)));
163159
sb.append("- ");
164160
sb.append(s);
165161
sb.append("\n");

hoptimator-api/src/main/java/com/linkedin/hoptimator/View.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.linkedin.hoptimator;
22

33
import java.util.List;
4-
import java.util.stream.Collectors;
54

65

76
public class View implements Deployable {

hoptimator-avro/src/main/java/com/linkedin/hoptimator/avro/AvroConverter.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import java.util.AbstractMap;
44
import java.util.List;
5+
import java.util.Objects;
6+
import java.util.Optional;
57
import java.util.stream.Collectors;
68

79
import org.apache.avro.Schema;
@@ -44,10 +46,10 @@ public static Schema avro(String namespace, String name, RelDataType dataType) {
4446
case BOOLEAN:
4547
return createAvroTypeWithNullability(Schema.Type.BOOLEAN, dataType.isNullable());
4648
case ARRAY:
47-
return createAvroSchemaWithNullability(Schema.createArray(avro(null, null, dataType.getComponentType())),
49+
return createAvroSchemaWithNullability(Schema.createArray(avro(null, null, Objects.requireNonNull(dataType.getComponentType()))),
4850
dataType.isNullable());
4951
case MAP:
50-
return createAvroSchemaWithNullability(Schema.createMap(avro(null, null, dataType.getValueType())),
52+
return createAvroSchemaWithNullability(Schema.createMap(avro(null, null, Objects.requireNonNull(dataType.getValueType()))),
5153
dataType.isNullable());
5254
case UNKNOWN:
5355
case NULL:
@@ -118,8 +120,11 @@ public static RelDataType rel(Schema schema, RelDataTypeFactory typeFactory, boo
118120
case UNION:
119121
boolean isNullable = schema.isNullable();
120122
if (schema.isNullable() && schema.getTypes().size() == 2) {
121-
Schema innerType = schema.getTypes().stream().filter(x -> x.getType() != Schema.Type.NULL).findFirst().get();
122-
return typeFactory.createTypeWithNullability(rel(innerType, typeFactory, true), true);
123+
Optional<Schema> innerType = schema.getTypes().stream().filter(x -> x.getType() != Schema.Type.NULL).findFirst();
124+
if (innerType.isEmpty()) {
125+
throw new IllegalArgumentException("Union schema must contain at least one non-null type");
126+
}
127+
return typeFactory.createTypeWithNullability(rel(innerType.get(), typeFactory, true), true);
123128
}
124129
// Since we collapse complex unions into separate fields, each of these fields needs to be nullable
125130
// as only one of the group will be present in any given record.

hoptimator-avro/src/main/java/com/linkedin/hoptimator/avro/AvroTableValidator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ private void validate(SchemaPlus schema, Table table, Table originalTable, Issue
5757
RelDataType originalRowType = originalTable.getRowType(typeFactory);
5858
Schema avroSchema = AvroConverter.avro("ns", "n", rowType);
5959
Schema originalAvroSchema = AvroConverter.avro("ns", "n", originalRowType);
60-
DatumWriter<Object> datumWriter = new GenericDatumWriter<Object>(originalAvroSchema);
60+
DatumWriter<Object> datumWriter = new GenericDatumWriter<>(originalAvroSchema);
6161
try (OutputStream out = new ByteArrayOutputStream();
62-
DataFileWriter<Object> dataFileWriter = new DataFileWriter<Object>(datumWriter)) {
62+
DataFileWriter<Object> dataFileWriter = new DataFileWriter<>(datumWriter)) {
6363
dataFileWriter.create(originalAvroSchema, out);
6464
for (Object obj : new RandomData(avroSchema, 1)) {
6565
dataFileWriter.append(obj);

hoptimator-avro/src/test/java/com/linkedin/hoptimator/avro/AvroConverterTest.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.linkedin.hoptimator.avro;
22

3+
import java.util.Objects;
4+
35
import org.apache.avro.Schema;
46
import org.apache.calcite.plan.RelOptUtil;
57
import org.apache.calcite.rel.type.RelDataType;
@@ -16,21 +18,21 @@ public class AvroConverterTest {
1618

1719
@Test
1820
public void convertsNestedSchemas() {
19-
// CHECKSTYLE:OFF
2021
String schemaString =
21-
"{\"type\":\"record\",\"name\":\"E\",\"namespace\":\"ns\",\"fields\":[{\"name\":\"h\",\"type\":[\"null\",{\"type\":\"record\",\"name\":\"H\",\"namespace\":\"ns\",\"fields\":[{\"name\":\"A\",\"type\":[\"null\",{\"type\":\"record\",\"name\":\"A\",\"fields\":[]}]}]}]}]}";
22-
// CHECKSTYLE:ON
22+
"{\"type\":\"record\",\"name\":\"E\",\"namespace\":\"ns\",\"fields\":["
23+
+ "{\"name\":\"h\",\"type\":[\"null\",{\"type\":\"record\",\"name\":\"H\",\"namespace\":\"ns\",\"fields\":["
24+
+ "{\"name\":\"A\",\"type\":[\"null\",{\"type\":\"record\",\"name\":\"A\",\"fields\":[]}]}]}]}]}";
2325

2426
Schema avroSchema1 = (new Schema.Parser()).parse(schemaString);
2527
RelDataType rel1 = AvroConverter.rel(avroSchema1);
2628
assertEquals(rel1.toString(), rel1.getFieldCount(), avroSchema1.getFields().size());
2729
assertNotNull(rel1.toString(), rel1.getField("h", false, false));
28-
RelDataType rel2 = rel1.getField("h", false, false).getType();
30+
RelDataType rel2 = Objects.requireNonNull(rel1.getField("h", false, false)).getType();
2931
assertTrue(rel2.toString(), rel2.isNullable());
3032
Schema avroSchema2 = avroSchema1.getField("h").schema().getTypes().get(1);
3133
assertEquals(rel2.toString(), rel2.getFieldCount(), avroSchema2.getFields().size());
3234
assertNotNull(rel2.toString(), rel2.getField("A", false, false));
33-
RelDataType rel3 = rel2.getField("A", false, false).getType();
35+
RelDataType rel3 = Objects.requireNonNull(rel2.getField("A", false, false)).getType();
3436
assertTrue(rel3.toString(), rel3.isNullable());
3537
Schema avroSchema3 = avroSchema2.getField("A").schema().getTypes().get(1);
3638
assertEquals(rel3.toString(), rel3.getFieldCount(), avroSchema3.getFields().size());
@@ -48,16 +50,21 @@ public void convertsNestedSchemas() {
4850

4951
@Test
5052
public void convertsNestedUnionSchemas() {
51-
String schemaString = "{\"type\":\"record\",\"name\":\"record\",\"namespace\":\"ns\",\"fields\":[{\"name\":\"event\",\"type\":[{\"type\":\"record\",\"name\":\"record_event1\",\"fields\":[{\"name\":\"strField\",\"type\":\"string\"}]},{\"type\":\"record\",\"name\":\"record_event2\",\"fields\":[{\"name\":\"strField\",\"type\":\"string\"}]}]}]}";
53+
String schemaString =
54+
"{\"type\":\"record\",\"name\":\"record\",\"namespace\":\"ns\",\"fields\":["
55+
+ "{\"name\":\"event\",\"type\":[{\"type\":\"record\",\"name\":\"record_event1\",\"fields\":["
56+
+ "{\"name\":\"strField\",\"type\":\"string\"}]},{\"type\":\"record\",\"name\":\"record_event2\",\"fields\":["
57+
+ "{\"name\":\"strField\",\"type\":\"string\"}]}]}]}";
58+
5259
Schema avroSchema1 = (new Schema.Parser()).parse(schemaString);
5360
RelDataType rel1 = AvroConverter.rel(avroSchema1);
5461
assertEquals(rel1.toString(), rel1.getFieldCount(), avroSchema1.getFields().size());
5562
assertNotNull(rel1.toString(), rel1.getField("event", false, false));
56-
RelDataType rel2 = rel1.getField("event", false, false).getType();
63+
RelDataType rel2 = Objects.requireNonNull(rel1.getField("event", false, false)).getType();
5764
assertTrue(rel2.isStruct());
5865
Schema avroSchema2 = avroSchema1.getField("event").schema();
5966
assertEquals(rel2.toString(), rel2.getFieldCount(), avroSchema2.getTypes().size());
60-
RelDataType rel3 = rel2.getField("record_event1", false, false).getType();
67+
RelDataType rel3 = Objects.requireNonNull(rel2.getField("record_event1", false, false)).getType();
6168
Schema avroSchema3 = avroSchema2.getTypes().get(0);
6269
assertEquals(rel3.toString(), rel3.getFieldCount(), avroSchema3.getFields().size());
6370
Schema avroSchema4 = AvroConverter.avro("NS", "R", rel1);

hoptimator-catalog/src/main/java/com/linkedin/hoptimator/catalog/DatabaseSchema.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@ public class DatabaseSchema extends AbstractSchema {
1212
private final Database database;
1313
private final Map<String, Table> tableMap;
1414

15-
public DatabaseSchema(Database database) {
15+
public DatabaseSchema(Database database, Map<String, Table> tableMap) {
1616
this.database = database;
17+
this.tableMap = tableMap;
18+
}
19+
20+
public static DatabaseSchema create(Database database) {
1721
try {
18-
this.tableMap = database.tables().stream().collect(Collectors.toMap(x -> x, x -> new ProtoTable(x, database)));
22+
Map<String, Table> tableMap = database.tables().stream().collect(Collectors.toMap(x -> x, x -> new ProtoTable(x, database)));
23+
return new DatabaseSchema(database, tableMap);
1924
} catch (Exception e) {
2025
throw new RuntimeException(e);
2126
}

hoptimator-catalog/src/main/java/com/linkedin/hoptimator/catalog/Resource.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
import java.io.IOException;
44
import java.io.InputStream;
55
import java.net.URL;
6+
import java.nio.charset.StandardCharsets;
67
import java.util.ArrayList;
78
import java.util.Collection;
89
import java.util.Enumeration;
910
import java.util.HashMap;
1011
import java.util.List;
1112
import java.util.Locale;
1213
import java.util.Map;
14+
import java.util.Objects;
1315
import java.util.Properties;
1416
import java.util.Scanner;
1517
import java.util.Set;
@@ -129,6 +131,20 @@ public int hashCode() {
129131
return toString().hashCode();
130132
}
131133

134+
@Override
135+
public boolean equals(Object o) {
136+
if (this == o) {
137+
return true;
138+
}
139+
if (o == null || getClass() != o.getClass()) {
140+
return false;
141+
}
142+
Resource resource = (Resource) o;
143+
return Objects.equals(template, resource.template)
144+
&& Objects.equals(properties, resource.properties)
145+
&& Objects.equals(inputs, resource.inputs);
146+
}
147+
132148
@Override
133149
public String toString() {
134150
StringBuilder sb = new StringBuilder();
@@ -305,7 +321,7 @@ public SimpleTemplate(Environment env, String template) {
305321

306322
@Override
307323
public String render(Resource resource) {
308-
StringBuffer sb = new StringBuffer();
324+
StringBuilder sb = new StringBuilder();
309325
Pattern p =
310326
Pattern.compile("([\\s\\-\\#]*)\\{\\{\\s*([\\w_\\-\\.]+)\\s*(:([\\w_\\-\\.]+))?\\s*((\\w+\\s*)*)\\s*\\}\\}");
311327
Matcher m = p.matcher(template);
@@ -318,9 +334,6 @@ public String render(Resource resource) {
318334
String defaultValue = m.group(4);
319335
String transform = m.group(5);
320336
String value = resource.getOrDefault(key, () -> env.getOrDefault(key, () -> defaultValue));
321-
if (value == null) {
322-
throw new IllegalArgumentException(template + " has no value for key " + key + ".");
323-
}
324337
String transformedValue = applyTransform(value, transform);
325338
String quotedPrefix = Matcher.quoteReplacement(prefix);
326339
String quotedValue = Matcher.quoteReplacement(transformedValue);
@@ -387,7 +400,7 @@ public Collection<Template> find(Resource resource) throws IOException {
387400
e.hasMoreElements(); ) {
388401
InputStream in = e.nextElement().openStream();
389402
StringBuilder sb = new StringBuilder();
390-
Scanner scanner = new Scanner(in);
403+
Scanner scanner = new Scanner(in, StandardCharsets.UTF_8);
391404
scanner.useDelimiter("\n");
392405
while (scanner.hasNext()) {
393406
sb.append(scanner.next());

hoptimator-catalog/src/main/java/com/linkedin/hoptimator/catalog/ScriptImplementor.java

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.Arrays;
55
import java.util.List;
66
import java.util.Map;
7+
import java.util.Objects;
78
import java.util.stream.Collectors;
89

910
import org.apache.calcite.plan.RelOptUtil;
@@ -128,26 +129,11 @@ public void implement(SqlWriter w) {
128129
class QueryImplementor implements ScriptImplementor {
129130
private final RelNode relNode;
130131

131-
public QueryImplementor(RelNode relNode) {
132-
this.relNode = relNode;
133-
}
134-
135-
@Override
136-
public void implement(SqlWriter w) {
137-
RelToSqlConverter converter = new RelToSqlConverter(w.getDialect());
138-
SqlImplementor.Result result = converter.visitRoot(relNode);
139-
SqlSelect select = result.asSelect();
140-
if (select.getSelectList() != null) {
141-
select.setSelectList((SqlNodeList) select.getSelectList().accept(REMOVE_ROW_CONSTRUCTOR));
142-
}
143-
w.literal(select.toSqlString(w.getDialect()).getSql());
144-
}
145-
146132
// A `ROW(...)` operator which will unparse as just `(...)`.
147-
private final SqlRowOperator IMPLIED_ROW_OPERATOR = new SqlRowOperator(""); // empty string name
133+
private static final SqlRowOperator IMPLIED_ROW_OPERATOR = new SqlRowOperator(""); // empty string name
148134

149135
// a shuttle that replaces `Row(...)` with just `(...)`
150-
private final SqlShuttle REMOVE_ROW_CONSTRUCTOR = new SqlShuttle() {
136+
private static final SqlShuttle REMOVE_ROW_CONSTRUCTOR = new SqlShuttle() {
151137
@Override
152138
public SqlNode visit(SqlCall call) {
153139
List<SqlNode> operands = call.getOperandList().stream().map(x -> x.accept(this)).collect(Collectors.toList());
@@ -159,6 +145,21 @@ public SqlNode visit(SqlCall call) {
159145
}
160146
}
161147
};
148+
149+
public QueryImplementor(RelNode relNode) {
150+
this.relNode = relNode;
151+
}
152+
153+
@Override
154+
public void implement(SqlWriter w) {
155+
RelToSqlConverter converter = new RelToSqlConverter(w.getDialect());
156+
SqlImplementor.Result result = converter.visitRoot(relNode);
157+
SqlSelect select = result.asSelect();
158+
if (select.getSelectList() != null) {
159+
select.setSelectList((SqlNodeList) Objects.requireNonNull(select.getSelectList().accept(REMOVE_ROW_CONSTRUCTOR)));
160+
}
161+
w.literal(select.toSqlString(w.getDialect()).getSql());
162+
}
162163
}
163164

164165
/**
@@ -297,7 +298,7 @@ public CompoundIdentifierImplementor(String database, String name) {
297298

298299
@Override
299300
public void implement(SqlWriter w) {
300-
SqlIdentifier identifier = new SqlIdentifier(Arrays.asList(new String[]{database, name}), SqlParserPos.ZERO);
301+
SqlIdentifier identifier = new SqlIdentifier(Arrays.asList(database, name), SqlParserPos.ZERO);
301302
identifier.unparse(w, 0, 0);
302303
}
303304
}
@@ -346,9 +347,10 @@ private static SqlDataTypeSpec toSpec(RelDataType dataType) {
346347
return maybeNullable(dataType,
347348
new SqlDataTypeSpec(new SqlRowTypeNameSpec(SqlParserPos.ZERO, fieldNames, fieldTypes), SqlParserPos.ZERO));
348349
}
349-
if (dataType.getComponentType() != null) {
350+
RelDataType componentType = dataType.getComponentType();
351+
if (componentType != null) {
350352
return maybeNullable(dataType, new SqlDataTypeSpec(new SqlCollectionTypeNameSpec(
351-
new SqlBasicTypeNameSpec(dataType.getComponentType().getSqlTypeName(), SqlParserPos.ZERO),
353+
new SqlBasicTypeNameSpec(componentType.getSqlTypeName(), SqlParserPos.ZERO),
352354
dataType.getSqlTypeName(), SqlParserPos.ZERO), SqlParserPos.ZERO));
353355
} else {
354356
return maybeNullable(dataType,

hoptimator-catalog/src/main/java/com/linkedin/hoptimator/catalog/builtin/DatagenSchemaFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ public Schema create(SchemaPlus parentSchema, String name, Map<String, Object> o
4444
.with("fields.NAME.length", "5")
4545
.with("fields.CEO.length", "5")
4646
.config("COMPANY")));
47-
return new DatabaseSchema(new Database(name, datagenTables));
47+
return DatabaseSchema.create(new Database(name, datagenTables));
4848
}
4949
}

0 commit comments

Comments
 (0)