Skip to content

Commit

Permalink
Add support Class.isEnum() and Class.isAnnotation()
Browse files Browse the repository at this point in the history
  • Loading branch information
hextriclosan committed Dec 22, 2024
1 parent ea5efd7 commit 8c53d55
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 3 deletions.
30 changes: 30 additions & 0 deletions tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -604,3 +604,33 @@ Superclass of java.util.HashMap: class java.util.AbstractMap
"#,
);
}

#[test]
fn should_check_if_class_is_enum() {
assert_success(
"samples.reflection.trivial.isenumexample.IsEnumExample",
r#"Is TimeUnit enum: true
Is TimeUnit.MINUTES enum: true
Is String enum: false
Is TimeUnit[].class enum: false
Is Runnable enum: false
Is int enum: false
Is void enum: false
"#,
);
}

#[test]
fn should_check_if_class_is_annotation() {
assert_success(
"samples.reflection.trivial.isannotationexample.IsAnnotationExample",
r#"@MyAnnotation is annotation: true
String.class is annotation: false
@InheritedAnnotation is annotation: true
@MyAnnotation subclass is annotation: true
@SourceAnnotation is annotation: true
Annotation array is annotation: false
int.class is annotation: false
"#,
);
}
66 changes: 66 additions & 0 deletions tests/test_data/IsAnnotationExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package samples.reflection.trivial.isannotationexample;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class IsAnnotationExample {
public static void main(String[] args) {
// Trivial Case: Simple annotation
System.out.print("@MyAnnotation is annotation: ");
System.out.println(MyAnnotation.class.isAnnotation()); // true

// Case 1: Non-annotation class
System.out.print("String.class is annotation: ");
System.out.println(String.class.isAnnotation()); // false

// Case 2: Annotation subclass (edge case)
System.out.print("@InheritedAnnotation is annotation: ");
System.out.println(InheritedAnnotation.class.isAnnotation()); // true
System.out.print("@MyAnnotation subclass is annotation: ");
System.out.println(SubAnnotation.class.isAnnotation()); // true

// Case 3: Runtime vs. compile-time retention
System.out.print("@SourceAnnotation is annotation: ");
System.out.println(SourceAnnotation.class.isAnnotation()); // true

// Case 4: Arrays and primitives
System.out.print("Annotation array is annotation: ");
System.out.println(MyAnnotation[].class.isAnnotation()); // false
System.out.print("int.class is annotation: ");
System.out.println(int.class.isAnnotation()); // false

// Case 5: Proxy class (edge case)
// Object proxy = java.lang.reflect.Proxy.newProxyInstance( //not yet implemented: INVOKEDYNAMIC
// IsAnnotationExample.class.getClassLoader(),
// new Class<?>[]{MyAnnotation.class},
// (proxyInstance, method, methodArgs) -> null
// );
// System.out.print("Proxy of @MyAnnotation is annotation: ");
// System.out.println(proxy.getClass().isAnnotation()); // false

}

// Annotation definitions
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyAnnotation {
}

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
@interface SourceAnnotation {
}

@MyAnnotation
@interface SubAnnotation {
}

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface InheritedAnnotation {
}
}
40 changes: 40 additions & 0 deletions tests/test_data/IsEnumExample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package samples.reflection.trivial.isenumexample;

import java.util.concurrent.TimeUnit;

public class IsEnumExample {
public static void main(String[] args) {
// 1. Basic Case: Enum class
System.out.print("Is TimeUnit enum: ");
System.out.println(TimeUnit.class.isEnum()); // true

// 2. Case: Enum constant's class
System.out.print("Is TimeUnit.MINUTES enum: ");
System.out.println(TimeUnit.MINUTES.getClass().isEnum()); // true

// 3. Case: Non-enum class
System.out.print("Is String enum: ");
System.out.println(String.class.isEnum()); // false

// 4. Case: Anonymous subclass of Enum (simulated with reflection)
// Enum<?> anonymousEnum = Enum.valueOf(TimeUnit.class, "MINUTES"); // Native Call Error: Native method jdk/internal/reflect/DirectMethodHandleAccessor$NativeAccessor:invoke0:(Ljava/lang/reflect/Method;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; not found
// System.out.print("Is Anonymous Enum enum: ");
// System.out.println(anonymousEnum.getClass().isEnum()); // true

// 5. Case: Array of enums
System.out.print("Is TimeUnit[].class enum: ");
System.out.println(TimeUnit[].class.isEnum()); // false

// 6. Case: Interface
System.out.print("Is Runnable enum: ");
System.out.println(Runnable.class.isEnum()); // false

// 7. Case: Primitive type
System.out.print("Is int enum: ");
System.out.println(int.class.isEnum()); // false

// 8. Case: Void type
System.out.print("Is void enum: ");
System.out.println(void.class.isEnum()); // false
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
16 changes: 13 additions & 3 deletions vm/src/system_native/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,19 @@ const _NATIVE: u16 = 0x00000100;
const INTERFACE: u16 = 0x00000200;
const ABSTRACT: u16 = 0x00000400;
const STRICT: u16 = 0x00000800;

const MODIFIERS: u16 =
PUBLIC | PROTECTED | PRIVATE | ABSTRACT | STATIC | FINAL | STRICT | INTERFACE;
const ANNOTATION: u16 = 0x00002000;
const ENUM: u16 = 0x00004000;

const MODIFIERS: u16 = PUBLIC
| PROTECTED
| PRIVATE
| ABSTRACT
| STATIC
| FINAL
| STRICT
| INTERFACE
| ENUM
| ANNOTATION;

pub(crate) fn get_modifiers_wrp(args: &[i32]) -> crate::error::Result<Vec<i32>> {
let modifiers = get_modifiers(args[0])?;
Expand Down

0 comments on commit 8c53d55

Please sign in to comment.