Skip to content
This repository has been archived by the owner on Oct 10, 2024. It is now read-only.

Commit

Permalink
Fix boxing and unboxing of annotated primitives
Browse files Browse the repository at this point in the history
Previously the operation did not honor an annotated primitive or boxed type as one which could be boxed or unboxed, respectively.

---------

Co-authored-by: Jake Wharton <[email protected]>
  • Loading branch information
invliD and JakeWharton authored Oct 30, 2023
1 parent 0d55218 commit d682f20
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 28 deletions.
65 changes: 37 additions & 28 deletions src/main/java/com/squareup/javapoet/TypeName.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ public TypeName annotated(List<AnnotationSpec> annotations) {
}

public TypeName withoutAnnotations() {
if (annotations.isEmpty()) {
return this;
}
return new TypeName(keyword);
}

Expand All @@ -144,14 +147,15 @@ public boolean isPrimitive() {
* other types types including unboxed primitives and {@code java.lang.Void}.
*/
public boolean isBoxedPrimitive() {
return this.equals(BOXED_BOOLEAN)
|| this.equals(BOXED_BYTE)
|| this.equals(BOXED_SHORT)
|| this.equals(BOXED_INT)
|| this.equals(BOXED_LONG)
|| this.equals(BOXED_CHAR)
|| this.equals(BOXED_FLOAT)
|| this.equals(BOXED_DOUBLE);
TypeName thisWithoutAnnotations = withoutAnnotations();
return thisWithoutAnnotations.equals(BOXED_BOOLEAN)
|| thisWithoutAnnotations.equals(BOXED_BYTE)
|| thisWithoutAnnotations.equals(BOXED_SHORT)
|| thisWithoutAnnotations.equals(BOXED_INT)
|| thisWithoutAnnotations.equals(BOXED_LONG)
|| thisWithoutAnnotations.equals(BOXED_CHAR)
|| thisWithoutAnnotations.equals(BOXED_FLOAT)
|| thisWithoutAnnotations.equals(BOXED_DOUBLE);
}

/**
Expand All @@ -160,16 +164,18 @@ public boolean isBoxedPrimitive() {
*/
public TypeName box() {
if (keyword == null) return this; // Doesn't need boxing.
if (this == VOID) return BOXED_VOID;
if (this == BOOLEAN) return BOXED_BOOLEAN;
if (this == BYTE) return BOXED_BYTE;
if (this == SHORT) return BOXED_SHORT;
if (this == INT) return BOXED_INT;
if (this == LONG) return BOXED_LONG;
if (this == CHAR) return BOXED_CHAR;
if (this == FLOAT) return BOXED_FLOAT;
if (this == DOUBLE) return BOXED_DOUBLE;
throw new AssertionError(keyword);
TypeName boxed = null;
if (keyword.equals(VOID.keyword)) boxed = BOXED_VOID;
else if (keyword.equals(BOOLEAN.keyword)) boxed = BOXED_BOOLEAN;
else if (keyword.equals(BYTE.keyword)) boxed = BOXED_BYTE;
else if (keyword.equals(SHORT.keyword)) boxed = BOXED_SHORT;
else if (keyword.equals(INT.keyword)) boxed = BOXED_INT;
else if (keyword.equals(LONG.keyword)) boxed = BOXED_LONG;
else if (keyword.equals(CHAR.keyword)) boxed = BOXED_CHAR;
else if (keyword.equals(FLOAT.keyword)) boxed = BOXED_FLOAT;
else if (keyword.equals(DOUBLE.keyword)) boxed = BOXED_DOUBLE;
else throw new AssertionError(keyword);
return annotations.isEmpty() ? boxed : boxed.annotated(annotations);
}

/**
Expand All @@ -180,16 +186,19 @@ public TypeName box() {
*/
public TypeName unbox() {
if (keyword != null) return this; // Already unboxed.
if (this.equals(BOXED_VOID)) return VOID;
if (this.equals(BOXED_BOOLEAN)) return BOOLEAN;
if (this.equals(BOXED_BYTE)) return BYTE;
if (this.equals(BOXED_SHORT)) return SHORT;
if (this.equals(BOXED_INT)) return INT;
if (this.equals(BOXED_LONG)) return LONG;
if (this.equals(BOXED_CHAR)) return CHAR;
if (this.equals(BOXED_FLOAT)) return FLOAT;
if (this.equals(BOXED_DOUBLE)) return DOUBLE;
throw new UnsupportedOperationException("cannot unbox " + this);
TypeName thisWithoutAnnotations = withoutAnnotations();
TypeName unboxed = null;
if (thisWithoutAnnotations.equals(BOXED_VOID)) unboxed = VOID;
else if (thisWithoutAnnotations.equals(BOXED_BOOLEAN)) unboxed = BOOLEAN;
else if (thisWithoutAnnotations.equals(BOXED_BYTE)) unboxed = BYTE;
else if (thisWithoutAnnotations.equals(BOXED_SHORT)) unboxed = SHORT;
else if (thisWithoutAnnotations.equals(BOXED_INT)) unboxed = INT;
else if (thisWithoutAnnotations.equals(BOXED_LONG)) unboxed = LONG;
else if (thisWithoutAnnotations.equals(BOXED_CHAR)) unboxed = CHAR;
else if (thisWithoutAnnotations.equals(BOXED_FLOAT)) unboxed = FLOAT;
else if (thisWithoutAnnotations.equals(BOXED_DOUBLE)) unboxed = DOUBLE;
else throw new UnsupportedOperationException("cannot unbox " + this);
return annotations.isEmpty() ? unboxed : unboxed.annotated(annotations);
}

@Override public final boolean equals(Object o) {
Expand Down
15 changes: 15 additions & 0 deletions src/test/java/com/squareup/javapoet/TypeNameTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
Expand All @@ -30,6 +31,8 @@

public class TypeNameTest {

private static final AnnotationSpec ANNOTATION_SPEC = AnnotationSpec.builder(ClassName.OBJECT).build();

protected <E extends Enum<E>> E generic(E[] values) {
return values[0];
}
Expand Down Expand Up @@ -173,6 +176,18 @@ protected static TestGeneric.NestedNonGeneric testNestedNonGeneric() {
assertThat(ClassName.get("java.lang", "String").isBoxedPrimitive()).isFalse();
assertThat(TypeName.VOID.isBoxedPrimitive()).isFalse();
assertThat(ClassName.get("java.lang", "Void").isBoxedPrimitive()).isFalse();
assertThat(ClassName.get("java.lang", "Integer")
.annotated(ANNOTATION_SPEC).isBoxedPrimitive()).isTrue();
}

@Test public void canBoxAnnotatedPrimitive() throws Exception {
assertThat(TypeName.BOOLEAN.annotated(ANNOTATION_SPEC).box()).isEqualTo(
ClassName.get("java.lang", "Boolean").annotated(ANNOTATION_SPEC));
}

@Test public void canUnboxAnnotatedPrimitive() throws Exception {
assertThat(ClassName.get("java.lang", "Boolean").annotated(ANNOTATION_SPEC)
.unbox()).isEqualTo(TypeName.BOOLEAN.annotated(ANNOTATION_SPEC));
}

private void assertEqualsHashCodeAndToString(TypeName a, TypeName b) {
Expand Down

0 comments on commit d682f20

Please sign in to comment.