Skip to content

Commit 27311db

Browse files
authored
Add support for fully generic classes. (firebase#1172)
Until now it was possible to annotate non-generic classes with `@Encodable`, while their properties could be generic with fully bound type variables. This change makes it possible to generate encoders for generic classes with generic properties, but with a compiler warning. Example: ```java @encodable public class GenericClass<T, U> { public T getT(); // warning generated public U getU(); // warning generated } ```
1 parent caac111 commit 27311db

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

encoders/firebase-encoders-processor/src/main/java/com/google/firebase/encoders/processor/getters/GetterFactory.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ private TypeMirror resolveTypeArguments(DeclaredType ownerType, TypeMirror gener
142142
genericType, ownerType));
143143
return genericType;
144144
}
145+
if (ownerType.getTypeArguments().get(index) instanceof TypeVariable) {
146+
messager.printMessage(
147+
Diagnostic.Kind.WARNING,
148+
String.format(
149+
"%s is a generic type, make sure you register encoders for types of %s that you plan to use.",
150+
ownerType, genericType));
151+
return genericType;
152+
}
145153
return resolveTypeArguments(ownerType, ownerType.getTypeArguments().get(index));
146154
}
147155
return genericType;

encoders/firebase-encoders-processor/src/test/java/com/google/firebase/encoders/processor/EncodableProcessorTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,27 @@ public void compile_withNonStaticNestedInsideGenericClass_shouldFail() {
115115
assertThat(result).hadErrorContaining("Could not infer type");
116116
}
117117

118+
@Test
119+
public void compile_withGenericClass_ShouldWarnAboutPotentialProblems() {
120+
Compilation result =
121+
javac()
122+
.withProcessors(new EncodableProcessor())
123+
.compile(
124+
JavaFileObjects.forSourceLines(
125+
"GenericClass",
126+
"import com.google.firebase.encoders.annotations.Encodable;",
127+
"@Encodable public class GenericClass<T, U> {",
128+
"public T getT() { return null; }",
129+
"public U getU() { return null; }",
130+
"}"));
131+
132+
assertThat(result).hadWarningContaining("GenericClass<T,U> is a generic type");
133+
assertThat(result)
134+
.generatedSourceFile("AutoGenericClassEncoder")
135+
.hasSourceEquivalentTo(
136+
JavaFileObjects.forResource("ExpectedGenericsEncoderWithUnknownType.java"));
137+
}
138+
118139
@Test
119140
public void compile_withMultipleGenericArgs_shouldCreateEncodersForAllKnownGenericArgs() {
120141
Compilation result =
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import com.google.firebase.encoders.EncodingException;
16+
import com.google.firebase.encoders.ObjectEncoder;
17+
import com.google.firebase.encoders.ObjectEncoderContext;
18+
import com.google.firebase.encoders.config.Configurator;
19+
import com.google.firebase.encoders.config.EncoderConfig;
20+
import java.io.IOException;
21+
import java.lang.Override;
22+
import javax.annotation.Generated;
23+
24+
/**
25+
* @hide */
26+
@Generated("com.google.firebase.encoders.processor.EncodableProcessor")
27+
public final class AutoGenericClassEncoder implements Configurator {
28+
public static final int CODEGEN_VERSION = 1;
29+
30+
public static final Configurator CONFIG = new AutoGenericClassEncoder();
31+
32+
private AutoGenericClassEncoder() {
33+
}
34+
35+
@Override
36+
public void configure(EncoderConfig<?> cfg) {
37+
cfg.registerEncoder(GenericClass.class, GenericClassEncoder.INSTANCE);
38+
}
39+
40+
private static final class GenericClassEncoder implements ObjectEncoder<GenericClass> {
41+
static final GenericClassEncoder INSTANCE = new GenericClassEncoder();
42+
43+
@Override
44+
public void encode(GenericClass value, ObjectEncoderContext ctx) throws IOException,
45+
EncodingException {
46+
ctx.add("t", value.getT());
47+
ctx.add("u", value.getU());
48+
}
49+
}
50+
}

0 commit comments

Comments
 (0)