2626import com .spotify .dataenum .processor .generator .match .MatchMethods ;
2727import com .spotify .dataenum .processor .parser .ParserException ;
2828import com .spotify .dataenum .processor .util .Iterables ;
29+ import com .squareup .javapoet .AnnotationSpec ;
2930import com .squareup .javapoet .FieldSpec ;
3031import com .squareup .javapoet .MethodSpec ;
32+ import com .squareup .javapoet .MethodSpec .Builder ;
3133import com .squareup .javapoet .ParameterizedTypeName ;
3234import com .squareup .javapoet .TypeName ;
3335import com .squareup .javapoet .TypeSpec ;
3436import com .squareup .javapoet .TypeVariableName ;
37+ import com .squareup .javapoet .WildcardTypeName ;
3538import java .util .ArrayList ;
39+ import java .util .Arrays ;
3640import java .util .List ;
3741import javax .annotation .Nonnull ;
3842import javax .annotation .Nullable ;
3943import javax .lang .model .element .Modifier ;
4044
4145public class ValueTypeFactory {
4246
47+ static final AnnotationSpec SUPPRESS_UNCHECKED_WARNINGS =
48+ AnnotationSpec .builder (SuppressWarnings .class ).addMember ("value" , "$S" , "unchecked" ).build ();
49+
4350 private ValueTypeFactory () {}
4451
4552 public static TypeSpec create (
@@ -163,7 +170,8 @@ private static MethodSpec createEquals(OutputValue value) throws ParserException
163170 result .addStatement ("if (other == this) return true" );
164171 result .addStatement ("if (!(other instanceof $T)) return false" , value .outputClass ());
165172
166- result .addStatement ("$1T o = ($1T) other" , value .outputClass ());
173+ TypeName wildCardTypeName = withWildCardTypeParameters (value );
174+ result .addStatement ("$1T o = ($1T) other" , wildCardTypeName );
167175 result .addCode ("$[return " );
168176 boolean first = true ;
169177 for (Parameter parameter : value .parameters ()) {
@@ -189,6 +197,18 @@ private static MethodSpec createEquals(OutputValue value) throws ParserException
189197 return result .build ();
190198 }
191199
200+ private static TypeName withWildCardTypeParameters (OutputValue value ) {
201+ if (!value .hasTypeVariables ()) {
202+ return value .outputClass ();
203+ }
204+
205+ TypeName [] wildCards = new TypeName [Iterables .sizeOf (value .typeVariables ())];
206+
207+ Arrays .fill (wildCards , WildcardTypeName .subtypeOf (TypeName .OBJECT ));
208+
209+ return ParameterizedTypeName .get (value .outputClass (), wildCards );
210+ }
211+
192212 private static MethodSpec createHashCode (OutputValue value ) {
193213 MethodSpec .Builder result =
194214 MethodSpec .methodBuilder ("hashCode" )
@@ -252,18 +272,34 @@ private static MethodSpec createToString(OutputValue value) {
252272 }
253273
254274 private static MethodSpec createAsSpecMethod (OutputValue value , OutputSpec spec ) {
275+ List <TypeVariableName > missingTypeVariables = extractMissingTypeVariablesForValue (value , spec );
276+
277+ Builder builder =
278+ MethodSpec .methodBuilder ("as" + spec .outputClass ().simpleName ())
279+ .addModifiers (Modifier .PUBLIC , Modifier .FINAL )
280+ .returns (spec .parameterizedOutputClass ())
281+ .addTypeVariables (missingTypeVariables )
282+ .addStatement ("return ($T) this" , spec .parameterizedOutputClass ());
283+
284+ // if there are type variables that this sub-type doesn't use, they will lead to 'unchecked
285+ // cast'
286+ // warnings when compiling the generated code. These warnings are safe to suppress, since this
287+ // sub type will never use those type variables.
288+ if (!missingTypeVariables .isEmpty ()) {
289+ builder .addAnnotation (SUPPRESS_UNCHECKED_WARNINGS );
290+ }
291+
292+ return builder .build ();
293+ }
294+
295+ static List <TypeVariableName > extractMissingTypeVariablesForValue (
296+ OutputValue value , OutputSpec spec ) {
255297 List <TypeVariableName > missingTypeVariables = new ArrayList <>();
256298 for (TypeVariableName typeVariableName : spec .typeVariables ()) {
257299 if (!Iterables .contains (value .typeVariables (), typeVariableName )) {
258300 missingTypeVariables .add (typeVariableName );
259301 }
260302 }
261-
262- return MethodSpec .methodBuilder ("as" + spec .outputClass ().simpleName ())
263- .addModifiers (Modifier .PUBLIC , Modifier .FINAL )
264- .returns (spec .parameterizedOutputClass ())
265- .addTypeVariables (missingTypeVariables )
266- .addStatement ("return ($T) this" , spec .parameterizedOutputClass ())
267- .build ();
303+ return missingTypeVariables ;
268304 }
269305}
0 commit comments