8227046: compiler implementation for sealed classes
8225056: VM support for sealed classes 8227044: javax.lang.model for sealed classes 8227045: Preview APIs support for sealed classes 8227047: Javadoc for sealed types 8245854: JVM TI Specification for sealed classes Co-authored-by: Harold Seigel <harold.seigel@oracle.com> Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com> Reviewed-by: mcimadamore, forax, darcy, dholmes, jlahoda, lfoltan, mchung, sspitsyn, vromero
This commit is contained in:
parent
567692e4ae
commit
d42bfef8a4
@ -650,6 +650,7 @@ INTERIM_LANGTOOLS_ADD_EXPORTS := \
|
||||
--add-exports java.base/sun.reflect.annotation=jdk.compiler.interim \
|
||||
--add-exports java.base/jdk.internal.jmod=jdk.compiler.interim \
|
||||
--add-exports java.base/jdk.internal.misc=jdk.compiler.interim \
|
||||
--add-exports java.base/sun.invoke.util=jdk.compiler.interim \
|
||||
#
|
||||
INTERIM_LANGTOOLS_MODULES_COMMA := $(strip $(subst $(SPACE),$(COMMA),$(strip \
|
||||
$(INTERIM_LANGTOOLS_MODULES))))
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -3160,8 +3160,8 @@ JDWP "Java(tm) Debug Wire Protocol"
|
||||
"canUnrestrictedlyRedefineClasses is false.")
|
||||
(Constant CLASS_ATTRIBUTE_CHANGE_NOT_IMPLEMENTED
|
||||
=72 "The new class version has a different NestHost, "
|
||||
"NestMembers, or Record class attribute and "
|
||||
"canUnrestrictedlyRedefineClasses is false.")
|
||||
"NestMembers, PermittedSubclasses, or Record class attribute "
|
||||
"and canUnrestrictedlyRedefineClasses is false.")
|
||||
(Constant NOT_IMPLEMENTED =99 "The functionality is not implemented in "
|
||||
"this virtual machine.")
|
||||
(Constant NULL_POINTER =100 "Invalid pointer.")
|
||||
|
@ -119,6 +119,7 @@ JVM_GetMethodTypeAnnotations
|
||||
JVM_GetNanoTimeAdjustment
|
||||
JVM_GetNestHost
|
||||
JVM_GetNestMembers
|
||||
JVM_GetPermittedSubclasses
|
||||
JVM_GetPrimitiveArrayElement
|
||||
JVM_GetProperties
|
||||
JVM_GetProtectionDomain
|
||||
|
@ -3212,6 +3212,41 @@ u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream
|
||||
return length;
|
||||
}
|
||||
|
||||
u2 ClassFileParser::parse_classfile_permitted_subclasses_attribute(const ClassFileStream* const cfs,
|
||||
const u1* const permitted_subclasses_attribute_start,
|
||||
TRAPS) {
|
||||
const u1* const current_mark = cfs->current();
|
||||
u2 length = 0;
|
||||
if (permitted_subclasses_attribute_start != NULL) {
|
||||
cfs->set_current(permitted_subclasses_attribute_start);
|
||||
cfs->guarantee_more(2, CHECK_0); // length
|
||||
length = cfs->get_u2_fast();
|
||||
}
|
||||
if (length < 1) {
|
||||
classfile_parse_error("PermittedSubclasses attribute is empty in class file %s", CHECK_0);
|
||||
}
|
||||
const int size = length;
|
||||
Array<u2>* const permitted_subclasses = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
|
||||
_permitted_subclasses = permitted_subclasses;
|
||||
|
||||
int index = 0;
|
||||
cfs->guarantee_more(2 * length, CHECK_0);
|
||||
for (int n = 0; n < length; n++) {
|
||||
const u2 class_info_index = cfs->get_u2_fast();
|
||||
check_property(
|
||||
valid_klass_reference_at(class_info_index),
|
||||
"Permitted subclass class_info_index %u has bad constant type in class file %s",
|
||||
class_info_index, CHECK_0);
|
||||
permitted_subclasses->at_put(index++, class_info_index);
|
||||
}
|
||||
assert(index == size, "wrong size");
|
||||
|
||||
// Restore buffer's current position.
|
||||
cfs->set_current(current_mark);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// Record {
|
||||
// u2 attribute_name_index;
|
||||
// u4 attribute_length;
|
||||
@ -3476,10 +3511,16 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
|
||||
CHECK);
|
||||
}
|
||||
|
||||
bool ClassFileParser::supports_sealed_types() {
|
||||
return _major_version == JVM_CLASSFILE_MAJOR_VERSION &&
|
||||
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
|
||||
Arguments::enable_preview();
|
||||
}
|
||||
|
||||
bool ClassFileParser::supports_records() {
|
||||
return _major_version == JVM_CLASSFILE_MAJOR_VERSION &&
|
||||
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
|
||||
Arguments::enable_preview();
|
||||
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
|
||||
Arguments::enable_preview();
|
||||
}
|
||||
|
||||
void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
|
||||
@ -3494,11 +3535,14 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
_inner_classes = Universe::the_empty_short_array();
|
||||
// Set nest members attribute to default sentinel
|
||||
_nest_members = Universe::the_empty_short_array();
|
||||
// Set _permitted_subclasses attribute to default sentinel
|
||||
_permitted_subclasses = Universe::the_empty_short_array();
|
||||
cfs->guarantee_more(2, CHECK); // attributes_count
|
||||
u2 attributes_count = cfs->get_u2_fast();
|
||||
bool parsed_sourcefile_attribute = false;
|
||||
bool parsed_innerclasses_attribute = false;
|
||||
bool parsed_nest_members_attribute = false;
|
||||
bool parsed_permitted_subclasses_attribute = false;
|
||||
bool parsed_nest_host_attribute = false;
|
||||
bool parsed_record_attribute = false;
|
||||
bool parsed_enclosingmethod_attribute = false;
|
||||
@ -3522,6 +3566,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
u4 nest_members_attribute_length = 0;
|
||||
const u1* record_attribute_start = NULL;
|
||||
u4 record_attribute_length = 0;
|
||||
const u1* permitted_subclasses_attribute_start = NULL;
|
||||
u4 permitted_subclasses_attribute_length = 0;
|
||||
|
||||
// Iterate over attributes
|
||||
while (attributes_count--) {
|
||||
@ -3738,6 +3784,26 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
}
|
||||
}
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
} else if (_major_version >= JAVA_15_VERSION) {
|
||||
// Check for PermittedSubclasses tag
|
||||
if (tag == vmSymbols::tag_permitted_subclasses()) {
|
||||
if (supports_sealed_types()) {
|
||||
if (parsed_permitted_subclasses_attribute) {
|
||||
classfile_parse_error("Multiple PermittedSubclasses attributes in class file %s", CHECK);
|
||||
}
|
||||
// Classes marked ACC_FINAL cannot have a PermittedSubclasses attribute.
|
||||
if (_access_flags.is_final()) {
|
||||
classfile_parse_error("PermittedSubclasses attribute in final class file %s", CHECK);
|
||||
}
|
||||
parsed_permitted_subclasses_attribute = true;
|
||||
permitted_subclasses_attribute_start = cfs->current();
|
||||
permitted_subclasses_attribute_length = attribute_length;
|
||||
}
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
} else {
|
||||
// Unknown attribute
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
}
|
||||
} else {
|
||||
// Unknown attribute
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
@ -3806,6 +3872,18 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed_permitted_subclasses_attribute) {
|
||||
const u2 num_subclasses = parse_classfile_permitted_subclasses_attribute(
|
||||
cfs,
|
||||
permitted_subclasses_attribute_start,
|
||||
CHECK);
|
||||
if (_need_verify) {
|
||||
guarantee_property(
|
||||
permitted_subclasses_attribute_length == sizeof(num_subclasses) + sizeof(u2) * num_subclasses,
|
||||
"Wrong PermittedSubclasses attribute length in class file %s", CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
if (_max_bootstrap_specifier_index >= 0) {
|
||||
guarantee_property(parsed_bootstrap_methods_attribute,
|
||||
"Missing BootstrapMethods attribute in class file %s", CHECK);
|
||||
@ -3873,6 +3951,7 @@ void ClassFileParser::apply_parsed_class_metadata(
|
||||
this_klass->set_nest_host_index(_nest_host);
|
||||
this_klass->set_local_interfaces(_local_interfaces);
|
||||
this_klass->set_annotations(_combined_annotations);
|
||||
this_klass->set_permitted_subclasses(_permitted_subclasses);
|
||||
this_klass->set_record_components(_record_components);
|
||||
// Delay the setting of _transitive_interfaces until after initialize_supers() in
|
||||
// fill_instance_klass(). It is because the _transitive_interfaces may be shared with
|
||||
@ -4681,12 +4760,34 @@ static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
|
||||
const Klass* const super = this_klass->super();
|
||||
|
||||
if (super != NULL) {
|
||||
const InstanceKlass* super_ik = InstanceKlass::cast(super);
|
||||
|
||||
if (super->is_final()) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_VerifyError(),
|
||||
"class %s cannot inherit from final class %s",
|
||||
this_klass->external_name(),
|
||||
super_ik->external_name());
|
||||
return;
|
||||
}
|
||||
|
||||
if (super_ik->is_sealed() && !super_ik->has_as_permitted_subclass(this_klass)) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_IncompatibleClassChangeError(),
|
||||
"class %s cannot inherit from sealed class %s",
|
||||
this_klass->external_name(),
|
||||
super_ik->external_name());
|
||||
return;
|
||||
}
|
||||
|
||||
// If the loader is not the boot loader then throw an exception if its
|
||||
// superclass is in package jdk.internal.reflect and its loader is not a
|
||||
// special reflection class loader
|
||||
if (!this_klass->class_loader_data()->is_the_null_class_loader_data()) {
|
||||
assert(super->is_instance_klass(), "super is not instance klass");
|
||||
PackageEntry* super_package = super->package();
|
||||
if (super_package != NULL &&
|
||||
super_package->name()->fast_compare(vmSymbols::jdk_internal_reflect()) == 0 &&
|
||||
@ -4742,6 +4843,19 @@ static void check_super_interface_access(const InstanceKlass* this_klass, TRAPS)
|
||||
for (int i = lng - 1; i >= 0; i--) {
|
||||
InstanceKlass* const k = local_interfaces->at(i);
|
||||
assert (k != NULL && k->is_interface(), "invalid interface");
|
||||
|
||||
if (k->is_sealed() && !k->has_as_permitted_subclass(this_klass)) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
vmSymbols::java_lang_IncompatibleClassChangeError(),
|
||||
"class %s cannot %s sealed interface %s",
|
||||
this_klass->external_name(),
|
||||
this_klass->is_interface() ? "extend" : "implement",
|
||||
k->external_name());
|
||||
return;
|
||||
}
|
||||
|
||||
Reflection::VerifyClassAccessResults vca_result =
|
||||
Reflection::verify_class_access(this_klass, k, false);
|
||||
if (vca_result != Reflection::ACCESS_OK) {
|
||||
@ -5677,6 +5791,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
|
||||
assert(NULL == _local_interfaces, "invariant");
|
||||
assert(NULL == _combined_annotations, "invariant");
|
||||
assert(NULL == _record_components, "invariant");
|
||||
assert(NULL == _permitted_subclasses, "invariant");
|
||||
|
||||
if (_has_final_method) {
|
||||
ik->set_has_final_method();
|
||||
@ -5965,6 +6080,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
|
||||
_inner_classes(NULL),
|
||||
_nest_members(NULL),
|
||||
_nest_host(0),
|
||||
_permitted_subclasses(NULL),
|
||||
_record_components(NULL),
|
||||
_local_interfaces(NULL),
|
||||
_transitive_interfaces(NULL),
|
||||
@ -6073,6 +6189,7 @@ void ClassFileParser::clear_class_metadata() {
|
||||
_methods = NULL;
|
||||
_inner_classes = NULL;
|
||||
_nest_members = NULL;
|
||||
_permitted_subclasses = NULL;
|
||||
_local_interfaces = NULL;
|
||||
_combined_annotations = NULL;
|
||||
_class_annotations = _class_type_annotations = NULL;
|
||||
@ -6109,6 +6226,10 @@ ClassFileParser::~ClassFileParser() {
|
||||
InstanceKlass::deallocate_record_components(_loader_data, _record_components);
|
||||
}
|
||||
|
||||
if (_permitted_subclasses != NULL && _permitted_subclasses != Universe::the_empty_short_array()) {
|
||||
MetadataFactory::free_array<u2>(_loader_data, _permitted_subclasses);
|
||||
}
|
||||
|
||||
// Free interfaces
|
||||
InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
|
||||
_local_interfaces, _transitive_interfaces);
|
||||
@ -6507,10 +6628,6 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st
|
||||
);
|
||||
return;
|
||||
}
|
||||
// Make sure super class is not final
|
||||
if (_super_klass->is_final()) {
|
||||
THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the transitive list of all unique interfaces implemented by this class
|
||||
|
@ -132,6 +132,7 @@ class ClassFileParser {
|
||||
Array<u2>* _inner_classes;
|
||||
Array<u2>* _nest_members;
|
||||
u2 _nest_host;
|
||||
Array<u2>* _permitted_subclasses;
|
||||
Array<RecordComponent*>* _record_components;
|
||||
Array<InstanceKlass*>* _local_interfaces;
|
||||
Array<InstanceKlass*>* _transitive_interfaces;
|
||||
@ -327,11 +328,16 @@ class ClassFileParser {
|
||||
const u1* const nest_members_attribute_start,
|
||||
TRAPS);
|
||||
|
||||
u2 parse_classfile_permitted_subclasses_attribute(const ClassFileStream* const cfs,
|
||||
const u1* const permitted_subclasses_attribute_start,
|
||||
TRAPS);
|
||||
|
||||
u2 parse_classfile_record_attribute(const ClassFileStream* const cfs,
|
||||
const ConstantPool* cp,
|
||||
const u1* const record_attribute_start,
|
||||
TRAPS);
|
||||
|
||||
bool supports_sealed_types();
|
||||
bool supports_records();
|
||||
|
||||
void parse_classfile_attributes(const ClassFileStream* const cfs,
|
||||
|
@ -173,6 +173,7 @@
|
||||
template(tag_runtime_invisible_type_annotations, "RuntimeInvisibleTypeAnnotations") \
|
||||
template(tag_enclosing_method, "EnclosingMethod") \
|
||||
template(tag_bootstrap_methods, "BootstrapMethods") \
|
||||
template(tag_permitted_subclasses, "PermittedSubclasses") \
|
||||
\
|
||||
/* exception klasses: at least all exceptions thrown by the VM have entries here */ \
|
||||
template(java_lang_ArithmeticException, "java/lang/ArithmeticException") \
|
||||
|
@ -567,6 +567,11 @@ JVM_IsRecord(JNIEnv *env, jclass cls);
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
JVM_GetRecordComponents(JNIEnv *env, jclass ofClass);
|
||||
|
||||
/* Sealed types - since JDK 15 */
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
JVM_GetPermittedSubclasses(JNIEnv *env, jclass current);
|
||||
|
||||
/* The following two reflection routines are still needed due to startup time issues */
|
||||
/*
|
||||
* java.lang.reflect.Method
|
||||
|
@ -147,6 +147,7 @@
|
||||
LOG_TAG(safepoint) \
|
||||
LOG_TAG(sampling) \
|
||||
LOG_TAG(scavenge) \
|
||||
LOG_TAG(sealed) \
|
||||
LOG_TAG(setting) \
|
||||
LOG_TAG(smr) \
|
||||
LOG_TAG(stacktrace) \
|
||||
|
@ -218,6 +218,57 @@ bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Called to verify that k is a permitted subclass of this class
|
||||
bool InstanceKlass::has_as_permitted_subclass(const InstanceKlass* k) const {
|
||||
Thread* THREAD = Thread::current();
|
||||
assert(k != NULL, "sanity check");
|
||||
assert(_permitted_subclasses != NULL && _permitted_subclasses != Universe::the_empty_short_array(),
|
||||
"unexpected empty _permitted_subclasses array");
|
||||
|
||||
if (log_is_enabled(Trace, class, sealed)) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_trace(class, sealed)("Checking for permitted subclass of %s in %s",
|
||||
k->external_name(), this->external_name());
|
||||
}
|
||||
|
||||
// Check that the class and its super are in the same module.
|
||||
if (k->module() != this->module()) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_trace(class, sealed)("Check failed for same module of permitted subclass %s and sealed class %s",
|
||||
k->external_name(), this->external_name());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!k->is_public() && !is_same_class_package(k)) {
|
||||
ResourceMark rm(THREAD);
|
||||
log_trace(class, sealed)("Check failed, subclass %s not public and not in the same package as sealed class %s",
|
||||
k->external_name(), this->external_name());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for a resolved cp entry, else fall back to a name check.
|
||||
// We don't want to resolve any class other than the one being checked.
|
||||
for (int i = 0; i < _permitted_subclasses->length(); i++) {
|
||||
int cp_index = _permitted_subclasses->at(i);
|
||||
if (_constants->tag_at(cp_index).is_klass()) {
|
||||
Klass* k2 = _constants->klass_at(cp_index, THREAD);
|
||||
assert(!HAS_PENDING_EXCEPTION, "Unexpected exception");
|
||||
if (k2 == k) {
|
||||
log_trace(class, sealed)("- class is listed at permitted_subclasses[%d] => cp[%d]", i, cp_index);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
Symbol* name = _constants->klass_name_at(cp_index);
|
||||
if (name == k->name()) {
|
||||
log_trace(class, sealed)("- Found it at permitted_subclasses[%d] => cp[%d]", i, cp_index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
log_trace(class, sealed)("- class is NOT a permitted subclass!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return nest-host class, resolving, validating and saving it if needed.
|
||||
// In cases where this is called from a thread that cannot do classloading
|
||||
// (such as a native JIT thread) then we simply return NULL, which in turn
|
||||
@ -484,6 +535,7 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass
|
||||
Klass(id),
|
||||
_nest_members(NULL),
|
||||
_nest_host(NULL),
|
||||
_permitted_subclasses(NULL),
|
||||
_record_components(NULL),
|
||||
_static_field_size(parser.static_field_size()),
|
||||
_nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
|
||||
@ -665,6 +717,13 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
|
||||
}
|
||||
set_nest_members(NULL);
|
||||
|
||||
if (permitted_subclasses() != NULL &&
|
||||
permitted_subclasses() != Universe::the_empty_short_array() &&
|
||||
!permitted_subclasses()->is_shared()) {
|
||||
MetadataFactory::free_array<jushort>(loader_data, permitted_subclasses());
|
||||
}
|
||||
set_permitted_subclasses(NULL);
|
||||
|
||||
// We should deallocate the Annotations instance if it's not in shared spaces.
|
||||
if (annotations() != NULL && !annotations()->is_shared()) {
|
||||
MetadataFactory::free_metadata(loader_data, annotations());
|
||||
@ -676,6 +735,12 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
|
||||
}
|
||||
}
|
||||
|
||||
bool InstanceKlass::is_sealed() const {
|
||||
return _permitted_subclasses != NULL &&
|
||||
_permitted_subclasses != Universe::the_empty_short_array() &&
|
||||
_permitted_subclasses->length() > 0;
|
||||
}
|
||||
|
||||
bool InstanceKlass::should_be_initialized() const {
|
||||
return !is_initialized();
|
||||
}
|
||||
@ -2414,6 +2479,7 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
}
|
||||
|
||||
it->push(&_nest_members);
|
||||
it->push(&_permitted_subclasses);
|
||||
it->push(&_record_components);
|
||||
}
|
||||
|
||||
@ -3342,6 +3408,7 @@ void InstanceKlass::print_on(outputStream* st) const {
|
||||
if (record_components() != NULL) {
|
||||
st->print(BULLET"record components: "); record_components()->print_value_on(st); st->cr();
|
||||
}
|
||||
st->print(BULLET"permitted subclasses: "); permitted_subclasses()->print_value_on(st); st->cr();
|
||||
if (java_mirror() != NULL) {
|
||||
st->print(BULLET"java mirror: ");
|
||||
java_mirror()->print_value_on(st);
|
||||
|
@ -198,6 +198,10 @@ class InstanceKlass: public Klass {
|
||||
// By always being set it makes nest-member access checks simpler.
|
||||
InstanceKlass* _nest_host;
|
||||
|
||||
// The PermittedSubclasses attribute. An array of shorts, where each is a
|
||||
// class info index for the class that is a permitted subclass.
|
||||
Array<jushort>* _permitted_subclasses;
|
||||
|
||||
// The contents of the Record attribute.
|
||||
Array<RecordComponent*>* _record_components;
|
||||
|
||||
@ -469,6 +473,10 @@ class InstanceKlass: public Klass {
|
||||
}
|
||||
bool is_record() const { return _record_components != NULL; }
|
||||
|
||||
// permitted subclasses
|
||||
Array<u2>* permitted_subclasses() const { return _permitted_subclasses; }
|
||||
void set_permitted_subclasses(Array<u2>* s) { _permitted_subclasses = s; }
|
||||
|
||||
private:
|
||||
// Called to verify that k is a member of this nest - does not look at k's nest-host
|
||||
bool has_nest_member(InstanceKlass* k, TRAPS) const;
|
||||
@ -484,6 +492,9 @@ public:
|
||||
// Check if this klass is a nestmate of k - resolves this nest-host and k's
|
||||
bool has_nestmate_access_to(InstanceKlass* k, TRAPS);
|
||||
|
||||
// Called to verify that k is a permitted subclass of this class
|
||||
bool has_as_permitted_subclass(const InstanceKlass* k) const;
|
||||
|
||||
enum InnerClassAttributeOffset {
|
||||
// From http://mirror.eng/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc10.html#18814
|
||||
inner_class_inner_class_info_offset = 0,
|
||||
@ -541,6 +552,9 @@ public:
|
||||
ClassState init_state() { return (ClassState)_init_state; }
|
||||
bool is_rewritten() const { return (_misc_flags & _misc_rewritten) != 0; }
|
||||
|
||||
// is this a sealed class
|
||||
bool is_sealed() const;
|
||||
|
||||
// defineClass specified verification
|
||||
bool should_verify_class() const {
|
||||
return (_misc_flags & _misc_should_verify_class) != 0;
|
||||
|
@ -2101,6 +2101,33 @@ JVM_ENTRY(jobjectArray, JVM_GetNestMembers(JNIEnv* env, jclass current))
|
||||
}
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(jobjectArray, JVM_GetPermittedSubclasses(JNIEnv* env, jclass current))
|
||||
{
|
||||
JVMWrapper("JVM_GetPermittedSubclasses");
|
||||
assert(!java_lang_Class::is_primitive(JNIHandles::resolve_non_null(current)), "should not be");
|
||||
Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(current));
|
||||
assert(c->is_instance_klass(), "must be");
|
||||
InstanceKlass* ik = InstanceKlass::cast(c);
|
||||
{
|
||||
JvmtiVMObjectAllocEventCollector oam;
|
||||
Array<u2>* subclasses = ik->permitted_subclasses();
|
||||
int length = subclasses == NULL ? 0 : subclasses->length();
|
||||
objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(),
|
||||
length, CHECK_NULL);
|
||||
objArrayHandle result(THREAD, r);
|
||||
for (int i = 0; i < length; i++) {
|
||||
int cp_index = subclasses->at(i);
|
||||
// This returns <package-name>/<class-name>.
|
||||
Symbol* klass_name = ik->constants()->klass_name_at(cp_index);
|
||||
assert(klass_name != NULL, "Unexpected null klass_name");
|
||||
Handle perm_subtype_h = java_lang_String::create_from_symbol(klass_name, CHECK_NULL);
|
||||
result->obj_at_put(i, perm_subtype_h());
|
||||
}
|
||||
return (jobjectArray)JNIHandles::make_local(THREAD, result());
|
||||
}
|
||||
}
|
||||
JVM_END
|
||||
|
||||
// Constant pool access //////////////////////////////////////////////////////////
|
||||
|
||||
JVM_ENTRY(jobject, JVM_GetClassConstantPool(JNIEnv *env, jclass cls))
|
||||
|
@ -6900,7 +6900,7 @@ class C2 extends C1 implements I2 {
|
||||
<synopsis>Get Classloader Classes</synopsis>
|
||||
<description>
|
||||
Returns an array of all classes which this class loader
|
||||
can find by name via
|
||||
can find by name via
|
||||
<externallink id="../api/java.base/java/lang/ClassLoader.html#loadClass(java.lang.String,boolean)">ClassLoader::loadClass</externallink>,
|
||||
<externallink id="../api/java.base/java/lang/Class.html#forName(java.lang.String,boolean,java.lang.ClassLoader)">Class::forName</externallink> and bytecode linkage.
|
||||
That is, all classes for which <code>initiating_loader</code>
|
||||
@ -7680,7 +7680,8 @@ class C2 extends C1 implements I2 {
|
||||
The retransformation must not add, remove or rename fields or methods, change the
|
||||
signatures of methods, change modifiers, or change inheritance.
|
||||
The retransformation must not change the <code>NestHost</code>,
|
||||
<code>NestMembers</code>, or <code>Record</code> attributes.
|
||||
<code>NestMembers</code>, <code>Record</code>, or <code>PermittedSubclasses</code>
|
||||
attributes.
|
||||
These restrictions may be lifted in future versions.
|
||||
See the error return description below for information on error codes
|
||||
returned if an unsupported retransformation is attempted.
|
||||
@ -7833,7 +7834,8 @@ class C2 extends C1 implements I2 {
|
||||
The redefinition must not add, remove or rename fields or methods, change the
|
||||
signatures of methods, change modifiers, or change inheritance.
|
||||
The redefinition must not change the <code>NestHost</code>,
|
||||
<code>NestMembers</code>, or <code>Record</code> attributes.
|
||||
<code>NestMembers</code>, <code>Record</code>, or <code>PermittedSubclasses</code>
|
||||
attributes.
|
||||
These restrictions may be lifted in future versions.
|
||||
See the error return description below for information on error codes
|
||||
returned if an unsupported redefinition is attempted.
|
||||
@ -15028,6 +15030,11 @@ typedef void (JNICALL *jvmtiEventVMInit)
|
||||
- Specify that RedefineClasses and RetransformClasses are not allowed
|
||||
to change the class file Record attribute.
|
||||
</change>
|
||||
<change date="13 May 2020" version="15.0.0">
|
||||
Minor update for new class file PermittedSubclasses attribute:
|
||||
- Specify that RedefineClasses and RetransformClasses are not allowed
|
||||
to change the class file PermittedSubclasses attribute.
|
||||
</change>
|
||||
</changehistory>
|
||||
|
||||
</specification>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -424,6 +424,26 @@ void JvmtiClassFileReconstituter::write_nest_members_attribute() {
|
||||
}
|
||||
}
|
||||
|
||||
// PermittedSubclasses {
|
||||
// u2 attribute_name_index;
|
||||
// u4 attribute_length;
|
||||
// u2 number_of_classes;
|
||||
// u2 classes[number_of_classes];
|
||||
// }
|
||||
void JvmtiClassFileReconstituter::write_permitted_subclasses_attribute() {
|
||||
Array<u2>* permitted_subclasses = ik()->permitted_subclasses();
|
||||
int number_of_classes = permitted_subclasses->length();
|
||||
int length = sizeof(u2) * (1 + number_of_classes); // '1 +' is for number_of_classes field
|
||||
|
||||
write_attribute_name_index("PermittedSubclasses");
|
||||
write_u4(length);
|
||||
write_u2(number_of_classes);
|
||||
for (int i = 0; i < number_of_classes; i++) {
|
||||
u2 class_cp_index = permitted_subclasses->at(i);
|
||||
write_u2(class_cp_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Record {
|
||||
// u2 attribute_name_index;
|
||||
// u4 attribute_length;
|
||||
@ -751,6 +771,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
|
||||
if (ik()->nest_members() != Universe::the_empty_short_array()) {
|
||||
++attr_count;
|
||||
}
|
||||
if (ik()->permitted_subclasses() != Universe::the_empty_short_array()) {
|
||||
++attr_count;
|
||||
}
|
||||
if (ik()->record_components() != NULL) {
|
||||
++attr_count;
|
||||
}
|
||||
@ -784,6 +807,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
|
||||
if (ik()->nest_members() != Universe::the_empty_short_array()) {
|
||||
write_nest_members_attribute();
|
||||
}
|
||||
if (ik()->permitted_subclasses() != Universe::the_empty_short_array()) {
|
||||
write_permitted_subclasses_attribute();
|
||||
}
|
||||
if (ik()->record_components() != NULL) {
|
||||
write_record_attribute();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -118,6 +118,7 @@ class JvmtiClassFileReconstituter : public JvmtiConstantPoolReconstituter {
|
||||
void write_bootstrapmethod_attribute();
|
||||
void write_nest_host_attribute();
|
||||
void write_nest_members_attribute();
|
||||
void write_permitted_subclasses_attribute();
|
||||
void write_record_attribute();
|
||||
|
||||
address writeable_address(size_t size);
|
||||
|
@ -854,6 +854,65 @@ static jvmtiError check_record_attribute(InstanceKlass* the_class, InstanceKlass
|
||||
}
|
||||
|
||||
|
||||
static jvmtiError check_permitted_subclasses_attribute(InstanceKlass* the_class,
|
||||
InstanceKlass* scratch_class) {
|
||||
// Check whether the class PermittedSubclasses attribute has been changed.
|
||||
Thread* thread = Thread::current();
|
||||
ResourceMark rm(thread);
|
||||
Array<u2>* the_permitted_subclasses = the_class->permitted_subclasses();
|
||||
Array<u2>* scr_permitted_subclasses = scratch_class->permitted_subclasses();
|
||||
bool the_subclasses_exist = the_permitted_subclasses != Universe::the_empty_short_array();
|
||||
bool scr_subclasses_exist = scr_permitted_subclasses != Universe::the_empty_short_array();
|
||||
int subclasses_len = the_permitted_subclasses->length();
|
||||
if (the_subclasses_exist && scr_subclasses_exist) {
|
||||
if (subclasses_len != scr_permitted_subclasses->length()) {
|
||||
log_trace(redefine, class, sealed)
|
||||
("redefined class %s attribute change error: PermittedSubclasses len=%d changed to len=%d",
|
||||
the_class->external_name(), subclasses_len, scr_permitted_subclasses->length());
|
||||
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
|
||||
}
|
||||
|
||||
// The order of entries in the PermittedSubclasses array is not specified so
|
||||
// we have to explicitly check for the same contents. We do this by copying
|
||||
// the referenced symbols into their own arrays, sorting them and then
|
||||
// comparing each element pair.
|
||||
|
||||
Symbol** the_syms = NEW_RESOURCE_ARRAY_RETURN_NULL(Symbol*, subclasses_len);
|
||||
Symbol** scr_syms = NEW_RESOURCE_ARRAY_RETURN_NULL(Symbol*, subclasses_len);
|
||||
|
||||
if (the_syms == NULL || scr_syms == NULL) {
|
||||
return JVMTI_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (int i = 0; i < subclasses_len; i++) {
|
||||
int the_cp_index = the_permitted_subclasses->at(i);
|
||||
int scr_cp_index = scr_permitted_subclasses->at(i);
|
||||
the_syms[i] = the_class->constants()->klass_name_at(the_cp_index);
|
||||
scr_syms[i] = scratch_class->constants()->klass_name_at(scr_cp_index);
|
||||
}
|
||||
|
||||
qsort(the_syms, subclasses_len, sizeof(Symbol*), symcmp);
|
||||
qsort(scr_syms, subclasses_len, sizeof(Symbol*), symcmp);
|
||||
|
||||
for (int i = 0; i < subclasses_len; i++) {
|
||||
if (the_syms[i] != scr_syms[i]) {
|
||||
log_trace(redefine, class, sealed)
|
||||
("redefined class %s attribute change error: PermittedSubclasses[%d]: %s changed to %s",
|
||||
the_class->external_name(), i, the_syms[i]->as_C_string(), scr_syms[i]->as_C_string());
|
||||
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
|
||||
}
|
||||
}
|
||||
} else if (the_subclasses_exist ^ scr_subclasses_exist) {
|
||||
const char* action_str = (the_subclasses_exist) ? "removed" : "added";
|
||||
log_trace(redefine, class, sealed)
|
||||
("redefined class %s attribute change error: PermittedSubclasses attribute %s",
|
||||
the_class->external_name(), action_str);
|
||||
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
|
||||
}
|
||||
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
|
||||
static bool can_add_or_delete(Method* m) {
|
||||
// Compatibility mode
|
||||
return (AllowRedefinitionToAddDeleteMethods &&
|
||||
@ -913,6 +972,12 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
|
||||
return err;
|
||||
}
|
||||
|
||||
// Check whether the PermittedSubclasses attribute has been changed.
|
||||
err = check_permitted_subclasses_attribute(the_class, scratch_class);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// Check whether class modifiers are the same.
|
||||
jushort old_flags = (jushort) the_class->access_flags().get_flags();
|
||||
jushort new_flags = (jushort) scratch_class->access_flags().get_flags();
|
||||
@ -1792,6 +1857,12 @@ bool VM_RedefineClasses::rewrite_cp_refs(InstanceKlass* scratch_class,
|
||||
return false;
|
||||
}
|
||||
|
||||
// rewrite constant pool references in the PermittedSubclasses attribute:
|
||||
if (!rewrite_cp_refs_in_permitted_subclasses_attribute(scratch_class)) {
|
||||
// propagate failure back to caller
|
||||
return false;
|
||||
}
|
||||
|
||||
// rewrite constant pool references in the methods:
|
||||
if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) {
|
||||
// propagate failure back to caller
|
||||
@ -1930,6 +2001,19 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_record_attribute(
|
||||
return true;
|
||||
}
|
||||
|
||||
// Rewrite constant pool references in the PermittedSubclasses attribute.
|
||||
bool VM_RedefineClasses::rewrite_cp_refs_in_permitted_subclasses_attribute(
|
||||
InstanceKlass* scratch_class) {
|
||||
|
||||
Array<u2>* permitted_subclasses = scratch_class->permitted_subclasses();
|
||||
assert(permitted_subclasses != NULL, "unexpected null permitted_subclasses");
|
||||
for (int i = 0; i < permitted_subclasses->length(); i++) {
|
||||
u2 cp_index = permitted_subclasses->at(i);
|
||||
permitted_subclasses->at_put(i, find_new_index(cp_index));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Rewrite constant pool references in the methods.
|
||||
bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
|
||||
InstanceKlass* scratch_class, TRAPS) {
|
||||
|
@ -479,6 +479,7 @@ class VM_RedefineClasses: public VM_Operation {
|
||||
InstanceKlass* scratch_class, TRAPS);
|
||||
bool rewrite_cp_refs_in_nest_attributes(InstanceKlass* scratch_class);
|
||||
bool rewrite_cp_refs_in_record_attribute(InstanceKlass* scratch_class, TRAPS);
|
||||
bool rewrite_cp_refs_in_permitted_subclasses_attribute(InstanceKlass* scratch_class);
|
||||
void rewrite_cp_refs_in_method(methodHandle method,
|
||||
methodHandle * new_method_p, TRAPS);
|
||||
bool rewrite_cp_refs_in_methods(InstanceKlass* scratch_class, TRAPS);
|
||||
|
@ -201,6 +201,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
private static final int ENUM = 0x00004000;
|
||||
private static final int SYNTHETIC = 0x00001000;
|
||||
|
||||
private static final ClassDesc[] EMPTY_CLASS_DESC_ARRAY = new ClassDesc[0];
|
||||
|
||||
private static native void registerNatives();
|
||||
static {
|
||||
registerNatives();
|
||||
@ -4382,4 +4384,69 @@ public final class Class<T> implements java.io.Serializable,
|
||||
@HotSpotIntrinsicCandidate
|
||||
public native boolean isHidden();
|
||||
|
||||
/**
|
||||
* {@preview Associated with sealed classes, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>sealed classes</i>, a preview
|
||||
* feature of the Java language. Preview features
|
||||
* may be removed in a future release, or upgraded to permanent
|
||||
* features of the Java language.}
|
||||
*
|
||||
* Returns an array containing {@code ClassDesc} objects representing all the
|
||||
* direct subclasses or direct implementation classes permitted to extend or implement this class or interface
|
||||
* if it is sealed. If this {@code Class} object represents a primitive type, {@code void}, an array type,
|
||||
* or a class or interface that is not sealed, an empty array is returned.
|
||||
*
|
||||
* @return an array of class descriptors of all the permitted subclasses of this class or interface
|
||||
*
|
||||
* @jls 8.1 Class Declarations
|
||||
* @jls 9.1 Interface Declarations
|
||||
* @since 15
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES, essentialAPI=false)
|
||||
public ClassDesc[] permittedSubclasses() {
|
||||
String[] subclassNames;
|
||||
if (isArray() || isPrimitive() || (subclassNames = getPermittedSubclasses0()).length == 0) {
|
||||
return EMPTY_CLASS_DESC_ARRAY;
|
||||
}
|
||||
ClassDesc[] constants = new ClassDesc[subclassNames.length];
|
||||
int i = 0;
|
||||
for (String subclassName : subclassNames) {
|
||||
try {
|
||||
constants[i++] = ClassDesc.of(subclassName.replace('/', '.'));
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new InternalError("Invalid type in permitted subclasses information: " + subclassName, iae);
|
||||
}
|
||||
}
|
||||
return constants;
|
||||
}
|
||||
|
||||
/**
|
||||
* * {@preview Associated with sealed classes, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>sealed classes</i>, a preview
|
||||
* feature of the Java language. Preview features
|
||||
* may be removed in a future release, or upgraded to permanent
|
||||
* features of the Java language.}
|
||||
*
|
||||
* Returns {@code true} if and only if this {@code Class} object represents a sealed class or interface.
|
||||
* If this {@code Class} object represents a primitive type, {@code void}, or an array type, this method returns
|
||||
* {@code false}.
|
||||
*
|
||||
* @return {@code true} if and only if this {@code Class} object represents a sealed class or interface.
|
||||
*
|
||||
* @jls 8.1 Class Declarations
|
||||
* @jls 9.1 Interface Declarations
|
||||
* @since 15
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES, essentialAPI=false)
|
||||
@SuppressWarnings("preview")
|
||||
public boolean isSealed() {
|
||||
if (isArray() || isPrimitive()) {
|
||||
return false;
|
||||
}
|
||||
return permittedSubclasses().length != 0;
|
||||
}
|
||||
|
||||
private native String[] getPermittedSubclasses0();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -63,6 +63,7 @@ public @interface PreviewFeature {
|
||||
// necessary for PreviewFeature in JDK 15 to declare the enum constant.
|
||||
TEXT_BLOCKS,
|
||||
RECORDS,
|
||||
SEALED_CLASSES,
|
||||
;
|
||||
}
|
||||
}
|
||||
|
@ -499,8 +499,8 @@ public class ClassReader {
|
||||
String nestHostClass = null;
|
||||
// - The offset of the NestMembers attribute, or 0.
|
||||
int nestMembersOffset = 0;
|
||||
// - The offset of the PermittedSubtypes attribute, or 0
|
||||
int permittedSubtypesOffset = 0;
|
||||
// - The offset of the PermittedSubclasses attribute, or 0
|
||||
int permittedSubclassesOffset = 0;
|
||||
// - The offset of the Record attribute, or 0.
|
||||
int recordOffset = 0;
|
||||
// - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
|
||||
@ -525,8 +525,8 @@ public class ClassReader {
|
||||
nestHostClass = readClass(currentAttributeOffset, charBuffer);
|
||||
} else if (Constants.NEST_MEMBERS.equals(attributeName)) {
|
||||
nestMembersOffset = currentAttributeOffset;
|
||||
} else if (Constants.PERMITTED_SUBTYPES.equals(attributeName)) {
|
||||
permittedSubtypesOffset = currentAttributeOffset;
|
||||
} else if (Constants.PERMITTED_SUBCLASSES.equals(attributeName)) {
|
||||
permittedSubclassesOffset = currentAttributeOffset;
|
||||
} else if (Constants.SIGNATURE.equals(attributeName)) {
|
||||
signature = readUTF8(currentAttributeOffset, charBuffer);
|
||||
} else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
|
||||
@ -704,14 +704,14 @@ public class ClassReader {
|
||||
}
|
||||
}
|
||||
|
||||
// Visit the PermittedSubtypes attribute.
|
||||
if (permittedSubtypesOffset != 0) {
|
||||
int numberOfPermittedSubtypes = readUnsignedShort(permittedSubtypesOffset);
|
||||
int currentPermittedSubtypeOffset = permittedSubtypesOffset + 2;
|
||||
while (numberOfPermittedSubtypes-- > 0) {
|
||||
classVisitor.visitPermittedSubtypeExperimental(
|
||||
readClass(currentPermittedSubtypeOffset, charBuffer));
|
||||
currentPermittedSubtypeOffset += 2;
|
||||
// Visit the PermittedSubclasses attribute.
|
||||
if (permittedSubclassesOffset != 0) {
|
||||
int numberOfPermittedSubclasses = readUnsignedShort(permittedSubclassesOffset);
|
||||
int currentPermittedSubclassOffset = permittedSubclassesOffset + 2;
|
||||
while (numberOfPermittedSubclasses-- > 0) {
|
||||
classVisitor.visitPermittedSubclassExperimental(
|
||||
readClass(currentPermittedSubclassOffset, charBuffer));
|
||||
currentPermittedSubclassOffset += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ package jdk.internal.org.objectweb.asm;
|
||||
/**
|
||||
* A visitor to visit a Java class. The methods of this class must be called in the following order:
|
||||
* {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
|
||||
* visitPermittedSubtype} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
|
||||
* visitPermittedSubclass} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
|
||||
* visitTypeAnnotation} | {@code visitAttribute} )* ( {@code visitNestMember} | {@code
|
||||
* visitInnerClass} | {@code visitField} | {@code visitMethod} )* {@code visitEnd}.
|
||||
*
|
||||
@ -287,19 +287,19 @@ public abstract class ClassVisitor {
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
|
||||
* will break existing code using it</b>. Visits a permitted subtypes. A permitted subtypes is one
|
||||
* of the allowed subtypes of the current class.
|
||||
* will break existing code using it</b>. Visits a permitted subclass. A permitted subclass is one
|
||||
* of the allowed subclasses of the current class.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @param permittedSubclass the internal name of a permitted subclass.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
|
||||
if (api != Opcodes.ASM9_EXPERIMENTAL) {
|
||||
throw new UnsupportedOperationException("This feature requires ASM9_EXPERIMENTAL");
|
||||
}
|
||||
if (cv != null) {
|
||||
cv.visitPermittedSubtypeExperimental(permittedSubtype);
|
||||
cv.visitPermittedSubclassExperimental(permittedSubclass);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -208,11 +208,11 @@ public class ClassWriter extends ClassVisitor {
|
||||
/** The 'classes' array of the NestMembers attribute, or {@literal null}. */
|
||||
private ByteVector nestMemberClasses;
|
||||
|
||||
/** The number_of_classes field of the PermittedSubtypes attribute, or 0. */
|
||||
private int numberOfPermittedSubtypeClasses;
|
||||
/** The number_of_classes field of the PermittedSubclasses attribute, or 0. */
|
||||
private int numberOfPermittedSubclassClasses;
|
||||
|
||||
/** The 'classes' array of the PermittedSubtypes attribute, or {@literal null}. */
|
||||
private ByteVector permittedSubtypeClasses;
|
||||
/** The 'classes' array of the PermittedSubclasses attribute, or {@literal null}. */
|
||||
private ByteVector permittedSubclassClasses;
|
||||
|
||||
/**
|
||||
* The record components of this class, stored in a linked list of {@link RecordComponentWriter}
|
||||
@ -406,17 +406,17 @@ public class ClassWriter extends ClassVisitor {
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @param permittedSubclass the internal name of a permitted subclass.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public final void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
if (permittedSubtypeClasses == null) {
|
||||
permittedSubtypeClasses = new ByteVector();
|
||||
public final void visitPermittedSubclassExperimental(final String permittedSubclass) {
|
||||
if (permittedSubclassClasses == null) {
|
||||
permittedSubclassClasses = new ByteVector();
|
||||
}
|
||||
++numberOfPermittedSubtypeClasses;
|
||||
permittedSubtypeClasses.putShort(symbolTable.addConstantClass(permittedSubtype).index);
|
||||
++numberOfPermittedSubclassClasses;
|
||||
permittedSubclassClasses.putShort(symbolTable.addConstantClass(permittedSubclass).index);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -607,10 +607,10 @@ public class ClassWriter extends ClassVisitor {
|
||||
size += 8 + nestMemberClasses.length;
|
||||
symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
|
||||
}
|
||||
if (permittedSubtypeClasses != null) {
|
||||
if (permittedSubclassClasses != null) {
|
||||
++attributesCount;
|
||||
size += 8 + permittedSubtypeClasses.length;
|
||||
symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES);
|
||||
size += 8 + permittedSubclassClasses.length;
|
||||
symbolTable.addConstantUtf8(Constants.PERMITTED_SUBCLASSES);
|
||||
}
|
||||
int recordComponentCount = 0;
|
||||
int recordSize = 0;
|
||||
@ -729,12 +729,12 @@ public class ClassWriter extends ClassVisitor {
|
||||
.putShort(numberOfNestMemberClasses)
|
||||
.putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
|
||||
}
|
||||
if (permittedSubtypeClasses != null) {
|
||||
if (permittedSubclassClasses != null) {
|
||||
result
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES))
|
||||
.putInt(permittedSubtypeClasses.length + 2)
|
||||
.putShort(numberOfPermittedSubtypeClasses)
|
||||
.putByteArray(permittedSubtypeClasses.data, 0, permittedSubtypeClasses.length);
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBCLASSES))
|
||||
.putInt(permittedSubclassClasses.length + 2)
|
||||
.putShort(numberOfPermittedSubclassClasses)
|
||||
.putByteArray(permittedSubclassClasses.data, 0, permittedSubclassClasses.length);
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_RECORD) != 0 || firstRecordComponent != null) {
|
||||
result
|
||||
@ -783,8 +783,8 @@ public class ClassWriter extends ClassVisitor {
|
||||
nestHostClassIndex = 0;
|
||||
numberOfNestMemberClasses = 0;
|
||||
nestMemberClasses = null;
|
||||
numberOfPermittedSubtypeClasses = 0;
|
||||
permittedSubtypeClasses = null;
|
||||
numberOfPermittedSubclassClasses = 0;
|
||||
permittedSubclassClasses = null;
|
||||
firstRecordComponent = null;
|
||||
lastRecordComponent = null;
|
||||
firstAttribute = null;
|
||||
|
@ -104,7 +104,7 @@ final class Constants {
|
||||
static final String MODULE_MAIN_CLASS = "ModuleMainClass";
|
||||
static final String NEST_HOST = "NestHost";
|
||||
static final String NEST_MEMBERS = "NestMembers";
|
||||
static final String PERMITTED_SUBTYPES = "PermittedSubtypes";
|
||||
static final String PERMITTED_SUBCLASSES = "PermittedSubclasses";
|
||||
static final String RECORD = "Record";
|
||||
|
||||
// ASM specific access flags.
|
||||
|
@ -252,13 +252,13 @@ public class ClassRemapper extends ClassVisitor {
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @param permittedSubclass the internal name of a permitted subclass.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
super.visitPermittedSubtypeExperimental(remapper.mapType(permittedSubtype));
|
||||
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
|
||||
super.visitPermittedSubclassExperimental(remapper.mapType(permittedSubclass));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,12 +160,12 @@ public class ClassNode extends ClassVisitor {
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
|
||||
* will break existing code using it</b>. The internal names of the permitted subtypes of this
|
||||
* will break existing code using it</b>. The internal names of the permitted subclasses of this
|
||||
* class. May be {@literal null}.
|
||||
*
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Deprecated public List<String> permittedSubtypesExperimental;
|
||||
@Deprecated public List<String> permittedSubclassesExperimental;
|
||||
|
||||
/** The record components of this class. May be {@literal null}. */
|
||||
public List<RecordComponentNode> recordComponents;
|
||||
@ -284,13 +284,13 @@ public class ClassNode extends ClassVisitor {
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @param permittedSubclass the internal name of a permitted subclass.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
permittedSubtypesExperimental = Util.add(permittedSubtypesExperimental, permittedSubtype);
|
||||
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
|
||||
permittedSubclassesExperimental = Util.add(permittedSubclassesExperimental, permittedSubclass);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -351,7 +351,7 @@ public class ClassNode extends ClassVisitor {
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void check(final int api) {
|
||||
if (api != Opcodes.ASM9_EXPERIMENTAL && permittedSubtypesExperimental != null) {
|
||||
if (api != Opcodes.ASM9_EXPERIMENTAL && permittedSubclassesExperimental != null) {
|
||||
throw new UnsupportedClassVersionException();
|
||||
}
|
||||
if (api < Opcodes.ASM8 && ((access & Opcodes.ACC_RECORD) != 0 || recordComponents != null)) {
|
||||
@ -473,10 +473,10 @@ public class ClassNode extends ClassVisitor {
|
||||
classVisitor.visitNestMember(nestMembers.get(i));
|
||||
}
|
||||
}
|
||||
// Visit the permitted subtypes.
|
||||
if (permittedSubtypesExperimental != null) {
|
||||
for (int i = 0, n = permittedSubtypesExperimental.size(); i < n; ++i) {
|
||||
classVisitor.visitPermittedSubtypeExperimental(permittedSubtypesExperimental.get(i));
|
||||
// Visit the permitted subclass.
|
||||
if (permittedSubclassesExperimental != null) {
|
||||
for (int i = 0, n = permittedSubclassesExperimental.size(); i < n; ++i) {
|
||||
classVisitor.visitPermittedSubclassExperimental(permittedSubclassesExperimental.get(i));
|
||||
}
|
||||
}
|
||||
// Visit the inner classes.
|
||||
|
@ -357,15 +357,15 @@ public class ASMifier extends Printer {
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @param permittedSubclass the internal name of a permitted subclass.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append("classWriter.visitPermittedSubtypeExperimental(");
|
||||
appendConstant(permittedSubtype);
|
||||
stringBuilder.append("classWriter.visitPermittedSubclassExperimental(");
|
||||
appendConstant(permittedSubclass);
|
||||
stringBuilder.append(END_PARAMETERS);
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
@ -356,15 +356,15 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @param permittedSubclass the internal name of a permitted subclass.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
|
||||
checkState();
|
||||
CheckMethodAdapter.checkInternalName(version, permittedSubtype, "permittedSubtype");
|
||||
super.visitPermittedSubtypeExperimental(permittedSubtype);
|
||||
CheckMethodAdapter.checkInternalName(version, permittedSubclass, "permittedSubclass");
|
||||
super.visitPermittedSubclassExperimental(permittedSubclass);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -488,15 +488,15 @@ public abstract class Printer {
|
||||
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
|
||||
* will break existing code using it</b>.
|
||||
*
|
||||
* <p>Visits a permitted subtypes. A permitted subtypes is one of the allowed subtypes of the
|
||||
* <p>Visits a permitted subclass. A permitted subtclass is one of the allowed subclasses of the
|
||||
* current class. See {@link
|
||||
* jdk.internal.org.objectweb.asm.ClassVisitor#visitPermittedSubtypeExperimental(String)}.
|
||||
* jdk.internal.org.objectweb.asm.ClassVisitor#visitPermittedSubclassExperimental(String)}.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @param permittedSubclass the internal name of a permitted subclass.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
|
@ -340,15 +340,15 @@ public class Textifier extends Printer {
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @param permittedSubclass the internal name of a permitted subclass.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append(tab).append("PERMITTEDSUBTYPE ");
|
||||
appendDescriptor(INTERNAL_NAME, permittedSubtype);
|
||||
stringBuilder.append(tab).append("PERMITTEDSUBCLASS ");
|
||||
appendDescriptor(INTERNAL_NAME, permittedSubclass);
|
||||
stringBuilder.append('\n');
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
@ -222,14 +222,14 @@ public final class TraceClassVisitor extends ClassVisitor {
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @param permittedSubclass the internal name of a permitted subclass.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
p.visitPermittedSubtypeExperimental(permittedSubtype);
|
||||
super.visitPermittedSubtypeExperimental(permittedSubtype);
|
||||
public void visitPermittedSubclassExperimental(final String permittedSubclass) {
|
||||
p.visitPermittedSubclassExperimental(permittedSubclass);
|
||||
super.visitPermittedSubclassExperimental(permittedSubclass);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -81,6 +81,7 @@ static JNINativeMethod methods[] = {
|
||||
{"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers},
|
||||
{"getRecordComponents0", "()[" RC, (void *)&JVM_GetRecordComponents},
|
||||
{"isRecord0", "()Z", (void *)&JVM_IsRecord},
|
||||
{"getPermittedSubclasses0", "()[" STR, (void *)&JVM_GetPermittedSubclasses},
|
||||
};
|
||||
|
||||
#undef OBJ
|
||||
|
@ -421,6 +421,10 @@ public enum SourceVersion {
|
||||
case "_":
|
||||
return version.compareTo(RELEASE_9) >= 0;
|
||||
|
||||
// case "non-sealed": can be added once it is a keyword only
|
||||
// dependent on release and not also preview features being
|
||||
// enabled.
|
||||
|
||||
// Keywords common across versions
|
||||
|
||||
// Modifiers
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -59,6 +59,40 @@ public enum Modifier {
|
||||
*/
|
||||
DEFAULT,
|
||||
/** The modifier {@code static} */ STATIC,
|
||||
|
||||
/**
|
||||
* {@preview Associated with sealed classes, a preview feature of the Java language.
|
||||
*
|
||||
* This enum constant is associated with <i>sealed classes</i>, a preview
|
||||
* feature of the Java language. Preview features
|
||||
* may be removed in a future release, or upgraded to permanent
|
||||
* features of the Java language.}
|
||||
*
|
||||
* The modifier {@code sealed}
|
||||
* @since 15
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
|
||||
essentialAPI=false)
|
||||
SEALED,
|
||||
|
||||
/**
|
||||
* {@preview Associated with sealed classes, a preview feature of the Java language.
|
||||
*
|
||||
* This enum constant is associated with <i>sealed classes</i>, a preview
|
||||
* feature of the Java language. Preview features
|
||||
* may be removed in a future release, or upgraded to permanent
|
||||
* features of the Java language.}
|
||||
*
|
||||
* The modifier {@code non-sealed}
|
||||
* @since 15
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
|
||||
essentialAPI=false)
|
||||
NON_SEALED {
|
||||
public String toString() {
|
||||
return "non-sealed";
|
||||
}
|
||||
},
|
||||
/** The modifier {@code final} */ FINAL,
|
||||
/** The modifier {@code transient} */ TRANSIENT,
|
||||
/** The modifier {@code volatile} */ VOLATILE,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -204,6 +204,29 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@preview Associated with sealed classes, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>sealed classes</i>, a preview
|
||||
* feature of the Java language. Preview features
|
||||
* may be removed in a future release, or upgraded to permanent
|
||||
* features of the Java language.}
|
||||
* Returns the permitted classes of this type element in
|
||||
* declaration order.
|
||||
*
|
||||
* @implSpec The default implementations of this method returns an
|
||||
* empty and unmodifiable list.
|
||||
*
|
||||
* @return the permitted classes, or an empty list if there are none
|
||||
*
|
||||
* @since 15
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
|
||||
essentialAPI=false)
|
||||
default List<? extends TypeMirror> getPermittedSubclasses() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the package of a top-level type and returns the
|
||||
* immediately lexically enclosing element for a {@linkplain
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -216,7 +216,7 @@ createThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode) {
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED:
|
||||
throwableClassName = "java/lang/UnsupportedOperationException";
|
||||
message = "class redefinition failed: attempted to change the class NestHost, NestMembers, or Record attribute";
|
||||
message = "class redefinition failed: attempted to change the class NestHost, NestMembers, Record, or PermittedSubclasses attribute";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,7 @@
|
||||
|
||||
package com.sun.source.tree;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.lang.model.element.Name;
|
||||
|
||||
@ -85,6 +86,28 @@ public interface ClassTree extends StatementTree {
|
||||
*/
|
||||
List<? extends Tree> getImplementsClause();
|
||||
|
||||
/**
|
||||
* {@preview Associated with sealed classes, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>sealed classes</i>, a preview
|
||||
* feature of the Java language. Preview features
|
||||
* may be removed in a future release, or upgraded to permanent
|
||||
* features of the Java language.}
|
||||
*
|
||||
* Returns the subclasses permitted by this type declaration.
|
||||
*
|
||||
* @implSpec this implementation returns an empty list
|
||||
*
|
||||
* @return the subclasses
|
||||
*
|
||||
* @since 15
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.SEALED_CLASSES,
|
||||
essentialAPI=false)
|
||||
default List<? extends Tree> getPermitsClause() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the members declared in this type declaration.
|
||||
* @return the members
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -178,12 +178,14 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
|
||||
* @param p {@inheritDoc}
|
||||
* @return the result of scanning
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
@Override
|
||||
public R visitClass(ClassTree node, P p) {
|
||||
R r = scan(node.getModifiers(), p);
|
||||
r = scanAndReduce(node.getTypeParameters(), p, r);
|
||||
r = scanAndReduce(node.getExtendsClause(), p, r);
|
||||
r = scanAndReduce(node.getImplementsClause(), p, r);
|
||||
r = scanAndReduce(node.getPermitsClause(), p, r);
|
||||
r = scanAndReduce(node.getMembers(), p, r);
|
||||
return r;
|
||||
}
|
||||
|
@ -366,6 +366,16 @@ public class Flags {
|
||||
*/
|
||||
public static final int GENERATED_MEMBER = 1<<24; // MethodSymbols and VarSymbols
|
||||
|
||||
/**
|
||||
* Flag to indicate sealed class/interface declaration.
|
||||
*/
|
||||
public static final long SEALED = 1L<<62; // ClassSymbols
|
||||
|
||||
/**
|
||||
* Flag to indicate that the class/interface was declared with the non-sealed modifier.
|
||||
*/
|
||||
public static final long NON_SEALED = 1L<<63; // ClassSymbols
|
||||
|
||||
/** Modifier masks.
|
||||
*/
|
||||
public static final int
|
||||
@ -385,14 +395,16 @@ public class Flags {
|
||||
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
|
||||
SYNCHRONIZED | FINAL | STRICTFP;
|
||||
public static final long
|
||||
ExtendedStandardFlags = (long)StandardFlags | DEFAULT,
|
||||
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT,
|
||||
ExtendedStandardFlags = (long)StandardFlags | DEFAULT | SEALED | NON_SEALED,
|
||||
ExtendedMemberClassFlags = (long)MemberClassFlags | SEALED | NON_SEALED,
|
||||
ExtendedClassFlags = (long)ClassFlags | SEALED | NON_SEALED,
|
||||
ModifierFlags = ((long)StandardFlags & ~INTERFACE) | DEFAULT | SEALED | NON_SEALED,
|
||||
InterfaceMethodMask = ABSTRACT | PRIVATE | STATIC | PUBLIC | STRICTFP | DEFAULT,
|
||||
AnnotationTypeElementMask = ABSTRACT | PUBLIC,
|
||||
LocalVarFlags = FINAL | PARAMETER,
|
||||
ReceiverParamFlags = PARAMETER;
|
||||
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
public static Set<Modifier> asModifierSet(long flags) {
|
||||
Set<Modifier> modifiers = modifierSets.get(flags);
|
||||
if (modifiers == null) {
|
||||
@ -402,6 +414,9 @@ public class Flags {
|
||||
if (0 != (flags & PRIVATE)) modifiers.add(Modifier.PRIVATE);
|
||||
if (0 != (flags & ABSTRACT)) modifiers.add(Modifier.ABSTRACT);
|
||||
if (0 != (flags & STATIC)) modifiers.add(Modifier.STATIC);
|
||||
if (0 != (flags & SEALED)) modifiers.add(Modifier.SEALED);
|
||||
if (0 != (flags & NON_SEALED))
|
||||
modifiers.add(Modifier.NON_SEALED);
|
||||
if (0 != (flags & FINAL)) modifiers.add(Modifier.FINAL);
|
||||
if (0 != (flags & TRANSIENT)) modifiers.add(Modifier.TRANSIENT);
|
||||
if (0 != (flags & VOLATILE)) modifiers.add(Modifier.VOLATILE);
|
||||
@ -492,7 +507,14 @@ public class Flags {
|
||||
PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API),
|
||||
MATCH_BINDING(Flags.MATCH_BINDING),
|
||||
MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER),
|
||||
RECORD(Flags.RECORD);
|
||||
RECORD(Flags.RECORD),
|
||||
SEALED(Flags.SEALED),
|
||||
NON_SEALED(Flags.NON_SEALED) {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "non-sealed";
|
||||
}
|
||||
};
|
||||
|
||||
Flag(long flag) {
|
||||
this.value = flag;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -167,7 +167,8 @@ public class Preview {
|
||||
public boolean isPreview(Feature feature) {
|
||||
if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF ||
|
||||
feature == Feature.REIFIABLE_TYPES_INSTANCEOF ||
|
||||
feature == Feature.RECORDS)
|
||||
feature == Feature.RECORDS ||
|
||||
feature == Feature.SEALED_CLASSES)
|
||||
return true;
|
||||
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
|
||||
//When real preview features will be added, this method can be implemented to return 'true'
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -209,6 +209,7 @@ public enum Source {
|
||||
PATTERN_MATCHING_IN_INSTANCEOF(JDK15, Fragments.FeaturePatternMatchingInstanceof, DiagKind.NORMAL),
|
||||
REIFIABLE_TYPES_INSTANCEOF(JDK15, Fragments.FeatureReifiableTypesInstanceof, DiagKind.PLURAL),
|
||||
RECORDS(JDK15, Fragments.FeatureRecords, DiagKind.PLURAL),
|
||||
SEALED_CLASSES(JDK15, Fragments.FeatureSealedClasses, DiagKind.PLURAL),
|
||||
;
|
||||
|
||||
enum DiagKind {
|
||||
|
@ -422,6 +422,14 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
return (flags() & ENUM) != 0;
|
||||
}
|
||||
|
||||
public boolean isSealed() {
|
||||
return (flags_field & SEALED) != 0;
|
||||
}
|
||||
|
||||
public boolean isNonSealed() {
|
||||
return (flags_field & NON_SEALED) != 0;
|
||||
}
|
||||
|
||||
public boolean isFinal() {
|
||||
return (flags_field & FINAL) != 0;
|
||||
}
|
||||
@ -1285,6 +1293,13 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
*/
|
||||
private List<RecordComponent> recordComponents = List.nil();
|
||||
|
||||
// sealed classes related fields
|
||||
/** The classes, or interfaces, permitted to extend this class, or interface
|
||||
*/
|
||||
public List<Symbol> permitted;
|
||||
|
||||
public boolean isPermittedExplicit = false;
|
||||
|
||||
public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
|
||||
super(TYP, flags, name, type, owner);
|
||||
this.members_field = null;
|
||||
@ -1293,6 +1308,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
this.sourcefile = null;
|
||||
this.classfile = null;
|
||||
this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType();
|
||||
this.permitted = List.nil();
|
||||
}
|
||||
|
||||
public ClassSymbol(long flags, Name name, Symbol owner) {
|
||||
@ -1601,6 +1617,11 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
public boolean isRecord() {
|
||||
return (flags_field & RECORD) != 0;
|
||||
}
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public List<Type> getPermittedSubclasses() {
|
||||
return permitted.map(s -> s.type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -730,7 +730,7 @@ public class Types {
|
||||
*/
|
||||
public FunctionDescriptor findDescriptorInternal(TypeSymbol origin,
|
||||
CompoundScope membersCache) throws FunctionDescriptorLookupError {
|
||||
if (!origin.isInterface() || (origin.flags() & ANNOTATION) != 0) {
|
||||
if (!origin.isInterface() || (origin.flags() & ANNOTATION) != 0 || origin.isSealed()) {
|
||||
//t must be an interface
|
||||
throw failure("not.a.functional.intf", origin);
|
||||
}
|
||||
|
@ -5027,6 +5027,90 @@ public class Attr extends JCTree.Visitor {
|
||||
// Get environment current at the point of class definition.
|
||||
Env<AttrContext> env = typeEnvs.get(c);
|
||||
|
||||
if (c.isSealed() &&
|
||||
!c.isEnum() &&
|
||||
!c.isPermittedExplicit &&
|
||||
c.permitted.isEmpty()) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.SealedClassMustHaveSubclasses);
|
||||
}
|
||||
|
||||
if (c.isSealed()) {
|
||||
Set<Symbol> permittedTypes = new HashSet<>();
|
||||
boolean sealedInUnnamed = c.packge().modle == syms.unnamedModule || c.packge().modle == syms.noModule;
|
||||
for (Symbol subTypeSym : c.permitted) {
|
||||
boolean isTypeVar = false;
|
||||
if (subTypeSym.type.getTag() == TYPEVAR) {
|
||||
isTypeVar = true; //error recovery
|
||||
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree),
|
||||
Errors.InvalidPermitsClause(Fragments.IsATypeVariable(subTypeSym.type)));
|
||||
}
|
||||
if (subTypeSym.isAnonymous() && !c.isEnum()) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), Errors.CantInheritFromSealed(c));
|
||||
}
|
||||
if (permittedTypes.contains(subTypeSym)) {
|
||||
DiagnosticPosition pos =
|
||||
env.enclClass.permitting.stream()
|
||||
.filter(permittedExpr -> TreeInfo.diagnosticPositionFor(subTypeSym, permittedExpr, true) != null)
|
||||
.limit(2).collect(List.collector()).get(1);
|
||||
log.error(pos, Errors.InvalidPermitsClause(Fragments.IsDuplicated(subTypeSym.type)));
|
||||
} else {
|
||||
permittedTypes.add(subTypeSym);
|
||||
}
|
||||
if (sealedInUnnamed) {
|
||||
if (subTypeSym.packge() != c.packge()) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), Errors.CantInheritFromSealed(c));
|
||||
}
|
||||
} else if (subTypeSym.packge().modle != c.packge().modle) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), Errors.CantInheritFromSealed(c));
|
||||
}
|
||||
if (subTypeSym == c.type.tsym || types.isSuperType(subTypeSym.type, c.type)) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, ((JCClassDecl)env.tree).permitting),
|
||||
Errors.InvalidPermitsClause(
|
||||
subTypeSym == c.type.tsym ?
|
||||
Fragments.MustNotBeSameClass :
|
||||
Fragments.MustNotBeSupertype(subTypeSym.type)
|
||||
)
|
||||
);
|
||||
} else if (!isTypeVar) {
|
||||
boolean thisIsASuper = types.directSupertypes(subTypeSym.type)
|
||||
.stream()
|
||||
.anyMatch(d -> d.tsym == c);
|
||||
if (!thisIsASuper) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree),
|
||||
Errors.InvalidPermitsClause(Fragments.DoesntExtendSealed(subTypeSym.type)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ClassSymbol> sealedSupers = types.directSupertypes(c.type)
|
||||
.stream()
|
||||
.filter(s -> s.tsym.isSealed())
|
||||
.map(s -> (ClassSymbol) s.tsym)
|
||||
.collect(List.collector());
|
||||
|
||||
if (sealedSupers.isEmpty()) {
|
||||
if ((c.flags_field & Flags.NON_SEALED) != 0) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.NonSealedWithNoSealedSupertype(c));
|
||||
}
|
||||
} else {
|
||||
if (c.isLocal() && !c.isEnum()) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.LocalClassesCantExtendSealed);
|
||||
}
|
||||
|
||||
for (ClassSymbol supertypeSym : sealedSupers) {
|
||||
if (!supertypeSym.permitted.contains(c.type.tsym)) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(c.type.tsym, env.tree), Errors.CantInheritFromSealed(supertypeSym));
|
||||
}
|
||||
}
|
||||
if (!c.isNonSealed() && !c.isFinal() && !c.isSealed()) {
|
||||
log.error(TreeInfo.diagnosticPositionFor(c, env.tree),
|
||||
c.isInterface() ?
|
||||
Errors.NonSealedOrSealedExpected :
|
||||
Errors.NonSealedSealedOrFinalExpected);
|
||||
}
|
||||
}
|
||||
|
||||
// The info.lint field in the envs stored in typeEnvs is deliberately uninitialized,
|
||||
// because the annotations were not available at the time the env was created. Therefore,
|
||||
// we look up the environment chain for the first enclosing environment for which the
|
||||
|
@ -160,6 +160,8 @@ public class Check {
|
||||
|
||||
allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) &&
|
||||
Feature.RECORDS.allowedInSource(source);
|
||||
allowSealed = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
|
||||
Feature.SEALED_CLASSES.allowedInSource(source);
|
||||
}
|
||||
|
||||
/** Character for synthetic names
|
||||
@ -195,6 +197,10 @@ public class Check {
|
||||
*/
|
||||
private final boolean allowRecords;
|
||||
|
||||
/** Are sealed classes allowed
|
||||
*/
|
||||
private final boolean allowSealed;
|
||||
|
||||
/* *************************************************************************
|
||||
* Errors and Warnings
|
||||
**************************************************************************/
|
||||
@ -1222,7 +1228,7 @@ public class Check {
|
||||
}
|
||||
}
|
||||
} else if (sym.owner.kind == TYP) {
|
||||
mask = (flags & RECORD) != 0 ? MemberRecordFlags : MemberClassFlags;
|
||||
mask = (flags & RECORD) != 0 ? MemberRecordFlags : ExtendedMemberClassFlags;
|
||||
if (sym.owner.owner.kind == PCK ||
|
||||
(sym.owner.flags_field & STATIC) != 0)
|
||||
mask |= STATIC;
|
||||
@ -1232,14 +1238,14 @@ public class Check {
|
||||
// Nested interfaces and enums are always STATIC (Spec ???)
|
||||
if ((flags & (INTERFACE | ENUM | RECORD)) != 0 ) implicit = STATIC;
|
||||
} else {
|
||||
mask = ClassFlags;
|
||||
mask = ExtendedClassFlags;
|
||||
}
|
||||
// Interfaces are always ABSTRACT
|
||||
if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;
|
||||
|
||||
if ((flags & ENUM) != 0) {
|
||||
// enums can't be declared abstract or final
|
||||
mask &= ~(ABSTRACT | FINAL);
|
||||
// enums can't be declared abstract, final, sealed or non-sealed
|
||||
mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED);
|
||||
implicit |= implicitEnumFinalFlag(tree);
|
||||
}
|
||||
if ((flags & RECORD) != 0) {
|
||||
@ -1294,7 +1300,13 @@ public class Check {
|
||||
(sym.kind == TYP ||
|
||||
checkDisjoint(pos, flags,
|
||||
ABSTRACT | NATIVE,
|
||||
STRICTFP))) {
|
||||
STRICTFP))
|
||||
&& checkDisjoint(pos, flags,
|
||||
FINAL,
|
||||
SEALED | NON_SEALED)
|
||||
&& checkDisjoint(pos, flags,
|
||||
SEALED,
|
||||
FINAL | NON_SEALED)) {
|
||||
// skip
|
||||
}
|
||||
return flags & (mask | ~ExtendedStandardFlags) | implicit;
|
||||
@ -1334,7 +1346,7 @@ public class Check {
|
||||
JCClassDecl cdef = (JCClassDecl) tree;
|
||||
for (JCTree defs: cdef.defs) {
|
||||
defs.accept(sts);
|
||||
if (sts.specialized) return 0;
|
||||
if (sts.specialized) return allowSealed ? SEALED : 0;
|
||||
}
|
||||
return FINAL;
|
||||
}
|
||||
|
@ -25,9 +25,11 @@
|
||||
|
||||
package com.sun.tools.javac.comp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.tools.JavaFileObject;
|
||||
|
||||
@ -711,6 +713,15 @@ public class TypeEnter implements Completer {
|
||||
}
|
||||
}
|
||||
|
||||
// Determine permits.
|
||||
ListBuffer<Symbol> permittedSubtypeSymbols = new ListBuffer<>();
|
||||
List<JCExpression> permittedTrees = tree.permitting;
|
||||
for (JCExpression permitted : permittedTrees) {
|
||||
permitted = clearTypeParams(permitted);
|
||||
Type pt = attr.attribBase(permitted, baseEnv, false, false, false);
|
||||
permittedSubtypeSymbols.append(pt.tsym);
|
||||
}
|
||||
|
||||
if ((sym.flags_field & ANNOTATION) != 0) {
|
||||
ct.interfaces_field = List.of(syms.annotationType);
|
||||
ct.all_interfaces_field = ct.interfaces_field;
|
||||
@ -719,6 +730,9 @@ public class TypeEnter implements Completer {
|
||||
ct.all_interfaces_field = (all_interfaces == null)
|
||||
? ct.interfaces_field : all_interfaces.toList();
|
||||
}
|
||||
|
||||
sym.permitted = permittedSubtypeSymbols.toList();
|
||||
sym.isPermittedExplicit = !permittedSubtypeSymbols.isEmpty();
|
||||
}
|
||||
//where:
|
||||
protected JCExpression clearTypeParams(JCExpression superType) {
|
||||
@ -729,7 +743,7 @@ public class TypeEnter implements Completer {
|
||||
private final class HierarchyPhase extends AbstractHeaderPhase implements Completer {
|
||||
|
||||
public HierarchyPhase() {
|
||||
super(CompletionCause.HIERARCHY_PHASE, new HeaderPhase());
|
||||
super(CompletionCause.HIERARCHY_PHASE, new PermitsPhase());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -803,6 +817,33 @@ public class TypeEnter implements Completer {
|
||||
|
||||
}
|
||||
|
||||
private final class PermitsPhase extends AbstractHeaderPhase {
|
||||
|
||||
public PermitsPhase() {
|
||||
super(CompletionCause.HIERARCHY_PHASE, new HeaderPhase());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runPhase(Env<AttrContext> env) {
|
||||
JCClassDecl tree = env.enclClass;
|
||||
if (!tree.sym.isAnonymous() || tree.sym.isEnum()) {
|
||||
for (Type supertype : types.directSupertypes(tree.sym.type)) {
|
||||
if (supertype.tsym.kind == TYP) {
|
||||
ClassSymbol supClass = (ClassSymbol) supertype.tsym;
|
||||
Env<AttrContext> supClassEnv = enter.getEnv(supClass);
|
||||
if (supClass.isSealed() &&
|
||||
!supClass.isPermittedExplicit &&
|
||||
supClassEnv != null &&
|
||||
supClassEnv.toplevel == env.toplevel) {
|
||||
supClass.permitted = supClass.permitted.append(tree.sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class HeaderPhase extends AbstractHeaderPhase {
|
||||
|
||||
public HeaderPhase() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -105,6 +105,10 @@ public class ClassReader {
|
||||
*/
|
||||
boolean allowModules;
|
||||
|
||||
/** Switch: allow sealed
|
||||
*/
|
||||
boolean allowSealedTypes;
|
||||
|
||||
/** Switch: allow records
|
||||
*/
|
||||
boolean allowRecords;
|
||||
@ -270,6 +274,8 @@ public class ClassReader {
|
||||
allowModules = Feature.MODULES.allowedInSource(source);
|
||||
allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) &&
|
||||
Feature.RECORDS.allowedInSource(source);
|
||||
allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
|
||||
Feature.SEALED_CLASSES.allowedInSource(source);
|
||||
|
||||
saveParameterNames = options.isSet(PARAMETERS);
|
||||
|
||||
@ -1202,7 +1208,23 @@ public class ClassReader {
|
||||
}
|
||||
bp = bp + attrLen;
|
||||
}
|
||||
}
|
||||
},
|
||||
new AttributeReader(names.PermittedSubclasses, V59, CLASS_ATTRIBUTE) {
|
||||
@Override
|
||||
protected boolean accepts(AttributeKind kind) {
|
||||
return super.accepts(kind) && allowSealedTypes;
|
||||
}
|
||||
protected void read(Symbol sym, int attrLen) {
|
||||
if (sym.kind == TYP) {
|
||||
ListBuffer<Symbol> subtypes = new ListBuffer<>();
|
||||
int numberOfPermittedSubtypes = nextChar();
|
||||
for (int i = 0; i < numberOfPermittedSubtypes; i++) {
|
||||
subtypes.add(poolReader.getClass(nextChar()));
|
||||
}
|
||||
((ClassSymbol)sym).permitted = subtypes.toList();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
for (AttributeReader r: readers)
|
||||
@ -2470,6 +2492,10 @@ public class ClassReader {
|
||||
for (int i = 0; i < methodCount; i++) skipMember();
|
||||
readClassAttrs(c);
|
||||
|
||||
if (c.permitted != null && !c.permitted.isEmpty()) {
|
||||
c.flags_field |= SEALED;
|
||||
}
|
||||
|
||||
// reset and read rest of classinfo
|
||||
bp = startbp;
|
||||
int n = nextChar();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -909,6 +909,21 @@ public class ClassWriter extends ClassFile {
|
||||
}
|
||||
}
|
||||
|
||||
/** Write "PermittedSubclasses" attribute.
|
||||
*/
|
||||
int writePermittedSubclassesIfNeeded(ClassSymbol csym) {
|
||||
if (csym.permitted.nonEmpty()) {
|
||||
int alenIdx = writeAttr(names.PermittedSubclasses);
|
||||
databuf.appendChar(csym.permitted.size());
|
||||
for (Symbol c : csym.permitted) {
|
||||
databuf.appendChar(poolWriter.putClass((ClassSymbol) c));
|
||||
}
|
||||
endAttr(alenIdx);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Write "bootstrapMethods" attribute.
|
||||
*/
|
||||
void writeBootstrapMethods() {
|
||||
@ -1635,6 +1650,10 @@ public class ClassWriter extends ClassFile {
|
||||
acount += writeRecordAttribute(c);
|
||||
}
|
||||
|
||||
if (target.hasSealedClasses()) {
|
||||
acount += writePermittedSubclassesIfNeeded(c);
|
||||
}
|
||||
|
||||
if (!poolWriter.bootstrapMethods.isEmpty()) {
|
||||
writeBootstrapMethods();
|
||||
acount++;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -183,4 +183,9 @@ public enum Target {
|
||||
return compareTo(JDK1_11) >= 0;
|
||||
}
|
||||
|
||||
/** Does the target VM support sealed types
|
||||
*/
|
||||
public boolean hasSealedClasses() {
|
||||
return compareTo(JDK1_15) >= 0;
|
||||
}
|
||||
}
|
||||
|
@ -186,6 +186,8 @@ public class JavacParser implements Parser {
|
||||
Feature.SWITCH_EXPRESSION.allowedInSource(source);
|
||||
this.allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) &&
|
||||
Feature.RECORDS.allowedInSource(source);
|
||||
this.allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) &&
|
||||
Feature.SEALED_CLASSES.allowedInSource(source);
|
||||
}
|
||||
|
||||
protected AbstractEndPosTable newEndPosTable(boolean keepEndPositions) {
|
||||
@ -223,6 +225,10 @@ public class JavacParser implements Parser {
|
||||
*/
|
||||
boolean allowRecords;
|
||||
|
||||
/** Switch: are sealed types allowed in this source level?
|
||||
*/
|
||||
boolean allowSealedTypes;
|
||||
|
||||
/** The type of the method receiver, as specified by a first "this" parameter.
|
||||
*/
|
||||
JCVariableDecl receiverParam;
|
||||
@ -2623,6 +2629,19 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
|
||||
//else intentional fall-through
|
||||
} else {
|
||||
if (isNonSealedClassStart(true)) {
|
||||
log.error(token.pos, Errors.SealedOrNonSealedLocalClassesNotAllowed);
|
||||
nextToken();
|
||||
nextToken();
|
||||
nextToken();
|
||||
return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.comment(CommentStyle.JAVADOC)));
|
||||
} else if (isSealedClassStart(true)) {
|
||||
checkSourceLevel(Feature.SEALED_CLASSES);
|
||||
log.error(token.pos, Errors.SealedOrNonSealedLocalClassesNotAllowed);
|
||||
nextToken();
|
||||
return List.of(classOrRecordOrInterfaceOrEnumDeclaration(modifiersOpt(), token.comment(CommentStyle.JAVADOC)));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isRecordStart() && allowRecords) {
|
||||
@ -3072,6 +3091,20 @@ public class JavacParser implements Parser {
|
||||
case MONKEYS_AT : flag = Flags.ANNOTATION; break;
|
||||
case DEFAULT : checkSourceLevel(Feature.DEFAULT_METHODS); flag = Flags.DEFAULT; break;
|
||||
case ERROR : flag = 0; nextToken(); break;
|
||||
case IDENTIFIER : {
|
||||
if (isNonSealedClassStart(false)) {
|
||||
flag = Flags.NON_SEALED;
|
||||
nextToken();
|
||||
nextToken();
|
||||
break;
|
||||
}
|
||||
if (isSealedClassStart(false)) {
|
||||
checkSourceLevel(Feature.SEALED_CLASSES);
|
||||
flag = Flags.SEALED;
|
||||
break;
|
||||
}
|
||||
break loop;
|
||||
}
|
||||
default: break loop;
|
||||
}
|
||||
if ((flags & flag) != 0) log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.RepeatedModifier);
|
||||
@ -3320,6 +3353,13 @@ public class JavacParser implements Parser {
|
||||
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14));
|
||||
}
|
||||
}
|
||||
if (name == names.sealed) {
|
||||
if (allowSealedTypes) {
|
||||
return Source.JDK15;
|
||||
} else if (shouldWarn) {
|
||||
log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -3714,9 +3754,18 @@ public class JavacParser implements Parser {
|
||||
nextToken();
|
||||
implementing = typeList();
|
||||
}
|
||||
List<JCExpression> permitting = List.nil();
|
||||
if (allowSealedTypes && token.kind == IDENTIFIER && token.name() == names.permits) {
|
||||
checkSourceLevel(Feature.SEALED_CLASSES);
|
||||
if ((mods.flags & Flags.SEALED) == 0) {
|
||||
log.error(token.pos, Errors.InvalidPermitsClause(Fragments.ClassIsNotSealed("class")));
|
||||
}
|
||||
nextToken();
|
||||
permitting = qualidentList(false);
|
||||
}
|
||||
List<JCTree> defs = classInterfaceOrRecordBody(name, false, false);
|
||||
JCClassDecl result = toP(F.at(pos).ClassDef(
|
||||
mods, name, typarams, extending, implementing, defs));
|
||||
mods, name, typarams, extending, implementing, permitting, defs));
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
@ -3793,9 +3842,19 @@ public class JavacParser implements Parser {
|
||||
nextToken();
|
||||
extending = typeList();
|
||||
}
|
||||
List<JCTree> defs = classInterfaceOrRecordBody(name, true, false);
|
||||
List<JCExpression> permitting = List.nil();
|
||||
if (allowSealedTypes && token.kind == IDENTIFIER && token.name() == names.permits) {
|
||||
checkSourceLevel(Feature.SEALED_CLASSES);
|
||||
if ((mods.flags & Flags.SEALED) == 0) {
|
||||
log.error(token.pos, Errors.InvalidPermitsClause(Fragments.ClassIsNotSealed("interface")));
|
||||
}
|
||||
nextToken();
|
||||
permitting = typeList();
|
||||
}
|
||||
List<JCTree> defs;
|
||||
defs = classInterfaceOrRecordBody(name, true, false);
|
||||
JCClassDecl result = toP(F.at(pos).ClassDef(
|
||||
mods, name, typarams, null, extending, defs));
|
||||
mods, name, typarams, null, extending, permitting, defs));
|
||||
attach(result, dc);
|
||||
return result;
|
||||
}
|
||||
@ -4141,16 +4200,62 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
|
||||
protected boolean isRecordStart() {
|
||||
if (token.kind == IDENTIFIER && token.name() == names.record &&
|
||||
if (token.kind == IDENTIFIER && token.name() == names.record &&
|
||||
(peekToken(TokenKind.IDENTIFIER, TokenKind.LPAREN) ||
|
||||
peekToken(TokenKind.IDENTIFIER, TokenKind.EOF) ||
|
||||
peekToken(TokenKind.IDENTIFIER, TokenKind.LT))) {
|
||||
checkSourceLevel(Feature.RECORDS);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
checkSourceLevel(Feature.RECORDS);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isNonSealedClassStart(boolean local) {
|
||||
if (isNonSealedIdentifier(token, 0)) {
|
||||
Token next = S.token(3);
|
||||
return allowedAfterSealedOrNonSealed(next, local, true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isNonSealedIdentifier(Token someToken, int lookAheadOffset) {
|
||||
if (someToken.name() == names.non && peekToken(lookAheadOffset, TokenKind.SUB, TokenKind.IDENTIFIER)) {
|
||||
Token tokenSub = S.token(lookAheadOffset + 1);
|
||||
Token tokenSealed = S.token(lookAheadOffset + 2);
|
||||
if (someToken.endPos == tokenSub.pos &&
|
||||
tokenSub.endPos == tokenSealed.pos &&
|
||||
tokenSealed.name() == names.sealed) {
|
||||
checkSourceLevel(Feature.SEALED_CLASSES);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isSealedClassStart(boolean local) {
|
||||
if (token.name() == names.sealed) {
|
||||
Token next = S.token(1);
|
||||
if (allowedAfterSealedOrNonSealed(next, local, false)) {
|
||||
checkSourceLevel(Feature.SEALED_CLASSES);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean allowedAfterSealedOrNonSealed(Token next, boolean local, boolean currentIsNonSealed) {
|
||||
return local ?
|
||||
switch (next.kind) {
|
||||
case MONKEYS_AT, ABSTRACT, FINAL, STRICTFP, CLASS, INTERFACE, ENUM -> true;
|
||||
default -> false;
|
||||
} :
|
||||
switch (next.kind) {
|
||||
case MONKEYS_AT, PUBLIC, PROTECTED, PRIVATE, ABSTRACT, STATIC, FINAL, STRICTFP, CLASS, INTERFACE, ENUM -> true;
|
||||
case IDENTIFIER -> isNonSealedIdentifier(next, currentIsNonSealed ? 3 : 1) || next.name() == names.sealed;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
/** MethodDeclaratorRest =
|
||||
* FormalParameters BracketsOpt [THROWS TypeList] ( MethodBody | [DEFAULT AnnotationValue] ";")
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,7 +30,6 @@ import javax.lang.model.*;
|
||||
import javax.lang.model.element.*;
|
||||
import static javax.lang.model.element.ElementKind.*;
|
||||
import static javax.lang.model.element.NestingKind.*;
|
||||
import static javax.lang.model.element.ModuleElement.DirectiveKind.*;
|
||||
import static javax.lang.model.element.ModuleElement.*;
|
||||
import javax.lang.model.type.*;
|
||||
import javax.lang.model.util.*;
|
||||
@ -39,7 +38,6 @@ import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
import com.sun.tools.javac.util.DefinedBy;
|
||||
@ -248,6 +246,7 @@ public class PrintingProcessor extends AbstractProcessor {
|
||||
}
|
||||
|
||||
printInterfaces(e);
|
||||
printPermittedSubclasses(e);
|
||||
}
|
||||
writer.println(" {");
|
||||
indentation++;
|
||||
@ -472,6 +471,7 @@ public class PrintingProcessor extends AbstractProcessor {
|
||||
case ENUM:
|
||||
modifiers.remove(Modifier.FINAL);
|
||||
modifiers.remove(Modifier.ABSTRACT);
|
||||
modifiers.remove(Modifier.SEALED);
|
||||
break;
|
||||
|
||||
case RECORD:
|
||||
@ -602,6 +602,17 @@ public class PrintingProcessor extends AbstractProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private void printPermittedSubclasses(TypeElement e) {
|
||||
List<? extends TypeMirror> subtypes = e.getPermittedSubclasses();
|
||||
if (!subtypes.isEmpty()) { // could remove this check with more complicated joining call
|
||||
writer.print(" permits ");
|
||||
writer.print(subtypes
|
||||
.stream()
|
||||
.map(subtype -> subtype.toString())
|
||||
.collect(Collectors.joining(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
private void printThrows(ExecutableElement e) {
|
||||
List<? extends TypeMirror> thrownTypes = e.getThrownTypes();
|
||||
final int size = thrownTypes.size();
|
||||
|
@ -2933,6 +2933,9 @@ compiler.misc.feature.reifiable.types.instanceof=\
|
||||
compiler.misc.feature.records=\
|
||||
records
|
||||
|
||||
compiler.misc.feature.sealed.classes=\
|
||||
sealed classes
|
||||
|
||||
compiler.warn.underscore.as.identifier=\
|
||||
as of release 9, ''_'' is a keyword, and may not be used as an identifier
|
||||
|
||||
@ -3435,6 +3438,65 @@ compiler.err.switch.case.unexpected.statement=\
|
||||
compiler.err.switch.mixing.case.types=\
|
||||
different case kinds used in the switch
|
||||
|
||||
###
|
||||
# errors related to sealed classes
|
||||
|
||||
# permits clause
|
||||
# 0: fragment
|
||||
compiler.err.invalid.permits.clause=\
|
||||
invalid permits clause\n\
|
||||
({0})
|
||||
|
||||
# 0: string
|
||||
compiler.misc.class.is.not.sealed=\
|
||||
{0} must be sealed
|
||||
|
||||
# 0: type
|
||||
compiler.misc.is.a.type.variable=\
|
||||
must not include type variables: {0}
|
||||
|
||||
# 0: type
|
||||
compiler.misc.is.duplicated=\
|
||||
must not contain duplicates: {0}
|
||||
|
||||
# 0: type
|
||||
compiler.misc.doesnt.extend.sealed=\
|
||||
subclass {0} must extend sealed class
|
||||
|
||||
compiler.misc.must.not.be.same.class=\
|
||||
illegal self-reference in permits clause
|
||||
|
||||
# 0: type
|
||||
compiler.misc.must.not.be.supertype=\
|
||||
illegal reference to supertype {0}
|
||||
|
||||
# other sealed types related errors
|
||||
|
||||
compiler.err.sealed.class.must.have.subclasses=\
|
||||
sealed class must have subclasses
|
||||
|
||||
# errors in subclasses of sealed classes
|
||||
# 0: symbol
|
||||
compiler.err.cant.inherit.from.sealed=\
|
||||
class is not allowed to extend sealed class: {0}
|
||||
|
||||
# 0: symbol
|
||||
compiler.err.non.sealed.with.no.sealed.supertype=\
|
||||
non-sealed modifier not allowed here\n\
|
||||
(class {0} does not have any sealed supertypes)
|
||||
|
||||
compiler.err.non.sealed.sealed.or.final.expected=\
|
||||
sealed, non-sealed or final modifiers expected
|
||||
|
||||
compiler.err.non.sealed.or.sealed.expected=\
|
||||
sealed or non-sealed modifiers expected
|
||||
|
||||
compiler.err.sealed.or.non.sealed.local.classes.not.allowed=\
|
||||
sealed or non-sealed local classes are not allowed
|
||||
|
||||
compiler.err.local.classes.cant.extend.sealed=\
|
||||
local classes must not extend sealed classes
|
||||
|
||||
###
|
||||
# errors related to records
|
||||
|
||||
|
@ -762,6 +762,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public JCExpression extending;
|
||||
/** the interfaces implemented by this class */
|
||||
public List<JCExpression> implementing;
|
||||
/** the subclasses allowed to extend this class, if sealed */
|
||||
public List<JCExpression> permitting;
|
||||
/** all variables and methods defined in this class */
|
||||
public List<JCTree> defs;
|
||||
/** the symbol */
|
||||
@ -771,6 +773,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
List<JCTypeParameter> typarams,
|
||||
JCExpression extending,
|
||||
List<JCExpression> implementing,
|
||||
List<JCExpression> permitting,
|
||||
List<JCTree> defs,
|
||||
ClassSymbol sym)
|
||||
{
|
||||
@ -779,6 +782,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
this.typarams = typarams;
|
||||
this.extending = extending;
|
||||
this.implementing = implementing;
|
||||
this.permitting = permitting;
|
||||
this.defs = defs;
|
||||
this.sym = sym;
|
||||
}
|
||||
@ -814,6 +818,11 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public List<JCExpression> getImplementsClause() {
|
||||
return implementing;
|
||||
}
|
||||
@SuppressWarnings("removal")
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public List<JCExpression> getPermitsClause() {
|
||||
return permitting;
|
||||
}
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public List<JCTree> getMembers() {
|
||||
return defs;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -564,6 +564,10 @@ public class Pretty extends JCTree.Visitor {
|
||||
print(" extends ");
|
||||
printExprs(tree.implementing);
|
||||
}
|
||||
if (tree.permitting.nonEmpty()) {
|
||||
print(" permits ");
|
||||
printExprs(tree.permitting);
|
||||
}
|
||||
} else {
|
||||
if ((tree.mods.flags & ENUM) != 0)
|
||||
print("enum " + tree.name);
|
||||
@ -578,6 +582,10 @@ public class Pretty extends JCTree.Visitor {
|
||||
print(" implements ");
|
||||
printExprs(tree.implementing);
|
||||
}
|
||||
if (tree.permitting.nonEmpty()) {
|
||||
print(" permits ");
|
||||
printExprs(tree.permitting);
|
||||
}
|
||||
}
|
||||
print(" ");
|
||||
if ((tree.mods.flags & ENUM) != 0) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -692,49 +692,81 @@ public class TreeInfo {
|
||||
/** Find the position for reporting an error about a symbol, where
|
||||
* that symbol is defined somewhere in the given tree. */
|
||||
public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree) {
|
||||
JCTree decl = declarationFor(sym, tree);
|
||||
return diagnosticPositionFor(sym, tree, false);
|
||||
}
|
||||
|
||||
public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final JCTree tree, boolean returnNullIfNotFound) {
|
||||
class DiagScanner extends DeclScanner {
|
||||
DiagScanner(Symbol sym) {
|
||||
super(sym);
|
||||
}
|
||||
|
||||
public void visitIdent(JCIdent that) {
|
||||
if (that.sym == sym) result = that;
|
||||
else super.visitIdent(that);
|
||||
}
|
||||
public void visitSelect(JCFieldAccess that) {
|
||||
if (that.sym == sym) result = that;
|
||||
else super.visitSelect(that);
|
||||
}
|
||||
}
|
||||
DiagScanner s = new DiagScanner(sym);
|
||||
tree.accept(s);
|
||||
JCTree decl = s.result;
|
||||
if (decl == null && returnNullIfNotFound) { return null; }
|
||||
return ((decl != null) ? decl : tree).pos();
|
||||
}
|
||||
|
||||
public static DiagnosticPosition diagnosticPositionFor(final Symbol sym, final List<? extends JCTree> trees) {
|
||||
return trees.stream().map(t -> TreeInfo.diagnosticPositionFor(sym, t)).filter(t -> t != null).findFirst().get();
|
||||
}
|
||||
|
||||
private static class DeclScanner extends TreeScanner {
|
||||
final Symbol sym;
|
||||
|
||||
DeclScanner(final Symbol sym) {
|
||||
this.sym = sym;
|
||||
}
|
||||
|
||||
JCTree result = null;
|
||||
public void scan(JCTree tree) {
|
||||
if (tree!=null && result==null)
|
||||
tree.accept(this);
|
||||
}
|
||||
public void visitTopLevel(JCCompilationUnit that) {
|
||||
if (that.packge == sym) result = that;
|
||||
else super.visitTopLevel(that);
|
||||
}
|
||||
public void visitModuleDef(JCModuleDecl that) {
|
||||
if (that.sym == sym) result = that;
|
||||
// no need to scan within module declaration
|
||||
}
|
||||
public void visitPackageDef(JCPackageDecl that) {
|
||||
if (that.packge == sym) result = that;
|
||||
else super.visitPackageDef(that);
|
||||
}
|
||||
public void visitClassDef(JCClassDecl that) {
|
||||
if (that.sym == sym) result = that;
|
||||
else super.visitClassDef(that);
|
||||
}
|
||||
public void visitMethodDef(JCMethodDecl that) {
|
||||
if (that.sym == sym) result = that;
|
||||
else super.visitMethodDef(that);
|
||||
}
|
||||
public void visitVarDef(JCVariableDecl that) {
|
||||
if (that.sym == sym) result = that;
|
||||
else super.visitVarDef(that);
|
||||
}
|
||||
public void visitTypeParameter(JCTypeParameter that) {
|
||||
if (that.type != null && that.type.tsym == sym) result = that;
|
||||
else super.visitTypeParameter(that);
|
||||
}
|
||||
}
|
||||
|
||||
/** Find the declaration for a symbol, where
|
||||
* that symbol is defined somewhere in the given tree. */
|
||||
public static JCTree declarationFor(final Symbol sym, final JCTree tree) {
|
||||
class DeclScanner extends TreeScanner {
|
||||
JCTree result = null;
|
||||
public void scan(JCTree tree) {
|
||||
if (tree!=null && result==null)
|
||||
tree.accept(this);
|
||||
}
|
||||
public void visitTopLevel(JCCompilationUnit that) {
|
||||
if (that.packge == sym) result = that;
|
||||
else super.visitTopLevel(that);
|
||||
}
|
||||
public void visitModuleDef(JCModuleDecl that) {
|
||||
if (that.sym == sym) result = that;
|
||||
// no need to scan within module declaration
|
||||
}
|
||||
public void visitPackageDef(JCPackageDecl that) {
|
||||
if (that.packge == sym) result = that;
|
||||
else super.visitPackageDef(that);
|
||||
}
|
||||
public void visitClassDef(JCClassDecl that) {
|
||||
if (that.sym == sym) result = that;
|
||||
else super.visitClassDef(that);
|
||||
}
|
||||
public void visitMethodDef(JCMethodDecl that) {
|
||||
if (that.sym == sym) result = that;
|
||||
else super.visitMethodDef(that);
|
||||
}
|
||||
public void visitVarDef(JCVariableDecl that) {
|
||||
if (that.sym == sym) result = that;
|
||||
else super.visitVarDef(that);
|
||||
}
|
||||
public void visitTypeParameter(JCTypeParameter that) {
|
||||
if (that.type != null && that.type.tsym == sym) result = that;
|
||||
else super.visitTypeParameter(that);
|
||||
}
|
||||
}
|
||||
DeclScanner s = new DeclScanner();
|
||||
DeclScanner s = new DeclScanner(sym);
|
||||
tree.accept(s);
|
||||
return s.result;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -160,12 +160,24 @@ public class TreeMaker implements JCTree.Factory {
|
||||
JCExpression extending,
|
||||
List<JCExpression> implementing,
|
||||
List<JCTree> defs)
|
||||
{
|
||||
return ClassDef(mods, name, typarams, extending, implementing, List.nil(), defs);
|
||||
}
|
||||
|
||||
public JCClassDecl ClassDef(JCModifiers mods,
|
||||
Name name,
|
||||
List<JCTypeParameter> typarams,
|
||||
JCExpression extending,
|
||||
List<JCExpression> implementing,
|
||||
List<JCExpression> permitting,
|
||||
List<JCTree> defs)
|
||||
{
|
||||
JCClassDecl tree = new JCClassDecl(mods,
|
||||
name,
|
||||
typarams,
|
||||
extending,
|
||||
implementing,
|
||||
permitting,
|
||||
defs,
|
||||
null);
|
||||
tree.pos = pos;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -115,6 +115,7 @@ public class TreeScanner extends Visitor {
|
||||
scan(tree.typarams);
|
||||
scan(tree.extending);
|
||||
scan(tree.implementing);
|
||||
scan(tree.permitting);
|
||||
scan(tree.defs);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -93,6 +93,7 @@ public abstract class Dependencies {
|
||||
MEMBER_ENTER,
|
||||
RECORD_PHASE,
|
||||
MEMBERS_PHASE,
|
||||
PERMITS_PHASE,
|
||||
OTHER;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,8 +25,6 @@
|
||||
|
||||
package com.sun.tools.javac.util;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Access to the compiler's name table. Standard names are defined,
|
||||
* as well as methods to create new names.
|
||||
@ -161,6 +159,7 @@ public class Names {
|
||||
public final Name Synthetic;
|
||||
public final Name Value;
|
||||
public final Name Varargs;
|
||||
public final Name PermittedSubclasses;
|
||||
|
||||
// members of java.lang.annotation.ElementType
|
||||
public final Name ANNOTATION_TYPE;
|
||||
@ -203,6 +202,7 @@ public class Names {
|
||||
public final Name bootstrap;
|
||||
|
||||
public final Name record;
|
||||
public final Name non;
|
||||
|
||||
// serialization members, used by records too
|
||||
public final Name serialPersistentFields;
|
||||
@ -210,6 +210,10 @@ public class Names {
|
||||
public final Name writeReplace;
|
||||
public final Name readObjectNoData;
|
||||
|
||||
// sealed types
|
||||
public final Name permits;
|
||||
public final Name sealed;
|
||||
|
||||
public final Name.Table table;
|
||||
|
||||
public Names(Context context) {
|
||||
@ -329,6 +333,7 @@ public class Names {
|
||||
Synthetic = fromString("Synthetic");
|
||||
Value = fromString("Value");
|
||||
Varargs = fromString("Varargs");
|
||||
PermittedSubclasses = fromString("PermittedSubclasses");
|
||||
|
||||
// members of java.lang.annotation.ElementType
|
||||
ANNOTATION_TYPE = fromString("ANNOTATION_TYPE");
|
||||
@ -367,11 +372,16 @@ public class Names {
|
||||
|
||||
bootstrap = fromString("bootstrap");
|
||||
record = fromString("record");
|
||||
non = fromString("non");
|
||||
|
||||
serialPersistentFields = fromString("serialPersistentFields");
|
||||
writeObject = fromString("writeObject");
|
||||
writeReplace = fromString("writeReplace");
|
||||
readObjectNoData = fromString("readObjectNoData");
|
||||
|
||||
// sealed types
|
||||
permits = fromString("permits");
|
||||
sealed = fromString("sealed");
|
||||
}
|
||||
|
||||
protected Name.Table createTable(Options options) {
|
||||
|
@ -112,8 +112,7 @@ public abstract class AbstractExecutableMemberWriter extends AbstractMemberWrite
|
||||
Content tdSummary) {
|
||||
ExecutableElement ee = (ExecutableElement)member;
|
||||
Content memberLink = HtmlTree.SPAN(HtmlStyle.memberNameLink,
|
||||
writer.getDocLink(context, te, ee,
|
||||
name(ee), false));
|
||||
writer.getDocLink(context, te, ee, name(ee), false));
|
||||
Content code = HtmlTree.CODE(memberLink);
|
||||
addParameters(ee, code);
|
||||
tdSummary.add(code);
|
||||
|
@ -30,6 +30,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.Element;
|
||||
@ -248,6 +249,32 @@ public class ClassWriterImpl extends SubWriterHolderWriter implements ClassWrite
|
||||
}
|
||||
}
|
||||
}
|
||||
List<? extends TypeMirror> permits = typeElement.getPermittedSubclasses();
|
||||
List<? extends TypeMirror> linkablePermits = permits.stream()
|
||||
.filter(t -> utils.isLinkable(utils.asTypeElement(t)))
|
||||
.collect(Collectors.toList());
|
||||
if (!linkablePermits.isEmpty()) {
|
||||
boolean isFirst = true;
|
||||
for (TypeMirror type : linkablePermits) {
|
||||
TypeElement tDoc = utils.asTypeElement(type);
|
||||
if (isFirst) {
|
||||
pre.add(DocletConstants.NL);
|
||||
pre.add("permits ");
|
||||
isFirst = false;
|
||||
} else {
|
||||
pre.add(", ");
|
||||
}
|
||||
Content link = getLink(new LinkInfoImpl(configuration,
|
||||
LinkInfoImpl.Kind.PERMITTED_SUBCLASSES,
|
||||
type));
|
||||
pre.add(link);
|
||||
}
|
||||
if (linkablePermits.size() < permits.size()) {
|
||||
Content c = new StringContent(resources.getText("doclet.not.exhaustive"));
|
||||
pre.add(" ");
|
||||
pre.add(HtmlTree.SPAN(HtmlStyle.permitsNote, c));
|
||||
}
|
||||
}
|
||||
classInfoTree.add(pre);
|
||||
}
|
||||
|
||||
|
@ -162,6 +162,11 @@ public class LinkInfoImpl extends LinkInfo {
|
||||
*/
|
||||
CLASS_SIGNATURE_PARENT_NAME,
|
||||
|
||||
/**
|
||||
* Permitted subclasses of a sealed type.
|
||||
*/
|
||||
PERMITTED_SUBCLASSES,
|
||||
|
||||
/**
|
||||
* The header for method documentation copied from parent.
|
||||
*/
|
||||
@ -360,6 +365,7 @@ public class LinkInfoImpl extends LinkInfo {
|
||||
case CLASS_TREE_PARENT:
|
||||
case TREE:
|
||||
case CLASS_SIGNATURE_PARENT_NAME:
|
||||
case PERMITTED_SUBCLASSES:
|
||||
excludeTypeParameterLinks = true;
|
||||
excludeTypeBounds = true;
|
||||
includeTypeInClassLinkLabel = false;
|
||||
|
@ -77,6 +77,7 @@ public enum HtmlStyle {
|
||||
packages,
|
||||
packageHierarchyLabel,
|
||||
packageUses,
|
||||
permitsNote,
|
||||
searchTagLink,
|
||||
searchTagResult,
|
||||
serializedPackageContainer,
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -62,6 +62,7 @@ doclet.navProperty=Property
|
||||
doclet.navEnum=Enum Constants
|
||||
doclet.navConstructor=Constr
|
||||
doclet.navMethod=Method
|
||||
doclet.not.exhaustive=(not exhaustive)
|
||||
doclet.Index=Index
|
||||
doclet.Window_Single_Index=Index
|
||||
doclet.Window_Split_Index={0}-Index
|
||||
|
@ -504,8 +504,18 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
void addSealed(TypeElement e) {
|
||||
if (e.getModifiers().contains(Modifier.SEALED)) {
|
||||
append("sealed");
|
||||
} else if (e.getModifiers().contains(Modifier.NON_SEALED)) {
|
||||
append("non-sealed");
|
||||
}
|
||||
}
|
||||
|
||||
void addModifiers(Set<Modifier> modifiers) {
|
||||
modifiers.stream().map(Modifier::toString).forEachOrdered(this::append);
|
||||
modifiers.stream()
|
||||
.map(Modifier::toString)
|
||||
.forEachOrdered(this::append);
|
||||
}
|
||||
|
||||
void append(String s) {
|
||||
@ -527,6 +537,7 @@ public class Utils {
|
||||
public String visitTypeAsInterface(TypeElement e, SortedSet<Modifier> mods) {
|
||||
addVisibilityModifier(mods);
|
||||
addStatic(mods);
|
||||
addSealed(e);
|
||||
return finalString("interface");
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -67,6 +67,7 @@ public abstract class Attribute {
|
||||
public static final String RuntimeInvisibleParameterAnnotations = "RuntimeInvisibleParameterAnnotations";
|
||||
public static final String RuntimeVisibleTypeAnnotations = "RuntimeVisibleTypeAnnotations";
|
||||
public static final String RuntimeInvisibleTypeAnnotations = "RuntimeInvisibleTypeAnnotations";
|
||||
public static final String PermittedSubclasses = "PermittedSubclasses";
|
||||
public static final String Signature = "Signature";
|
||||
public static final String SourceDebugExtension = "SourceDebugExtension";
|
||||
public static final String SourceFile = "SourceFile";
|
||||
@ -142,6 +143,7 @@ public abstract class Attribute {
|
||||
standardAttributes.put(RuntimeVisibleParameterAnnotations, RuntimeVisibleParameterAnnotations_attribute.class);
|
||||
standardAttributes.put(RuntimeVisibleTypeAnnotations, RuntimeVisibleTypeAnnotations_attribute.class);
|
||||
standardAttributes.put(RuntimeInvisibleTypeAnnotations, RuntimeInvisibleTypeAnnotations_attribute.class);
|
||||
standardAttributes.put(PermittedSubclasses, PermittedSubclasses_attribute.class);
|
||||
standardAttributes.put(Signature, Signature_attribute.class);
|
||||
standardAttributes.put(SourceDebugExtension, SourceDebugExtension_attribute.class);
|
||||
standardAttributes.put(SourceFile, SourceFile_attribute.class);
|
||||
@ -208,6 +210,7 @@ public abstract class Attribute {
|
||||
R visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, P p);
|
||||
R visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, P p);
|
||||
R visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, P p);
|
||||
R visitPermittedSubclasses(PermittedSubclasses_attribute attr, P p);
|
||||
R visitSignature(Signature_attribute attr, P p);
|
||||
R visitSourceDebugExtension(SourceDebugExtension_attribute attr, P p);
|
||||
R visitSourceFile(SourceFile_attribute attr, P p);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -695,6 +695,16 @@ public class ClassWriter {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitPermittedSubclasses(PermittedSubclasses_attribute attr, ClassOutputStream out) {
|
||||
int n = attr.subtypes.length;
|
||||
out.writeShort(n);
|
||||
for (int i = 0 ; i < n ; i++) {
|
||||
out.writeShort(attr.subtypes[i]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSignature(Signature_attribute attr, ClassOutputStream out) {
|
||||
out.writeShort(attr.signature_index);
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.sun.tools.classfile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info;
|
||||
|
||||
public class PermittedSubclasses_attribute extends Attribute {
|
||||
|
||||
public int[] subtypes;
|
||||
|
||||
PermittedSubclasses_attribute(ClassReader cr, int name_index, int length) throws IOException {
|
||||
super(name_index, length);
|
||||
int number_of_classes = cr.readUnsignedShort();
|
||||
subtypes = new int[number_of_classes];
|
||||
for (int i = 0; i < number_of_classes; i++)
|
||||
subtypes[i] = cr.readUnsignedShort();
|
||||
}
|
||||
|
||||
public PermittedSubclasses_attribute(int name_index, int[] subtypes) {
|
||||
super(name_index, 2);
|
||||
this.subtypes = subtypes;
|
||||
}
|
||||
|
||||
public CONSTANT_Class_info[] getSubtypes(ConstantPool constant_pool) throws ConstantPoolException {
|
||||
return IntStream.of(subtypes)
|
||||
.mapToObj(i -> {
|
||||
try {
|
||||
return constant_pool.getClassInfo(i);
|
||||
} catch (ConstantPoolException ex) {
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
}).toArray(CONSTANT_Class_info[]::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <R, D> R accept(Visitor<R, D> visitor, D data) {
|
||||
return visitor.visitPermittedSubclasses(this, data);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -68,7 +68,7 @@ import com.sun.tools.classfile.RuntimeParameterAnnotations_attribute;
|
||||
import com.sun.tools.classfile.RuntimeVisibleAnnotations_attribute;
|
||||
import com.sun.tools.classfile.RuntimeVisibleParameterAnnotations_attribute;
|
||||
import com.sun.tools.classfile.RuntimeVisibleTypeAnnotations_attribute;
|
||||
import com.sun.tools.classfile.Signature;
|
||||
import com.sun.tools.classfile.PermittedSubclasses_attribute;
|
||||
import com.sun.tools.classfile.Signature_attribute;
|
||||
import com.sun.tools.classfile.SourceDebugExtension_attribute;
|
||||
import com.sun.tools.classfile.SourceFile_attribute;
|
||||
@ -83,10 +83,6 @@ import static com.sun.tools.classfile.AccessFlags.*;
|
||||
import com.sun.tools.javac.util.Assert;
|
||||
import com.sun.tools.javac.util.StringUtils;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/*
|
||||
* A writer for writing Attributes as text.
|
||||
*
|
||||
@ -885,6 +881,22 @@ public class AttributeWriter extends BasicWriter
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitPermittedSubclasses(PermittedSubclasses_attribute attr, Void ignore) {
|
||||
println("PermittedSubclasses:");
|
||||
indent(+1);
|
||||
try {
|
||||
CONSTANT_Class_info[] subtypes = attr.getSubtypes(constant_pool);
|
||||
for (int i = 0; i < subtypes.length; i++) {
|
||||
println(constantWriter.stringValue(subtypes[i]));
|
||||
}
|
||||
indent(-1);
|
||||
} catch (ConstantPoolException ex) {
|
||||
throw new AssertionError(ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitSignature(Signature_attribute attr, Void ignore) {
|
||||
print("Signature: #" + attr.signature_index);
|
||||
|
95
test/hotspot/jtreg/runtime/modules/SealedModuleTest.java
Normal file
95
test/hotspot/jtreg/runtime/modules/SealedModuleTest.java
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225056
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @library /test/lib ..
|
||||
* @compile sealedP1/SuperClass.jcod
|
||||
* @compile --enable-preview --source ${jdk.version} sealedP1/C1.java sealedP2/C2.java sealedP3/C3.java
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @compile/module=java.base java/lang/ModuleHelper.java
|
||||
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. --enable-preview -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SealedModuleTest
|
||||
*/
|
||||
|
||||
public class SealedModuleTest {
|
||||
|
||||
// Test sub-classing a sealed super class in a named module. In this test,
|
||||
// sealed class sealedP1/SuperClass permits sealedP1.C1, sealedP2.C2, and
|
||||
// sealedP3.C3. All three of those classes extend sealedP1/SuperClass.
|
||||
|
||||
public static void main(String args[]) throws Throwable {
|
||||
Object m1x, m2x;
|
||||
|
||||
// Get the class loader for SealedModuleTest and assume it's also used
|
||||
// to load the other classes.
|
||||
ClassLoader this_cldr = AccessCheckRead.class.getClassLoader();
|
||||
|
||||
// Define a module for packages sealedP1 and sealedP2.
|
||||
m1x = ModuleHelper.ModuleObject("module_one", this_cldr,
|
||||
new String[] { "sealedP1", "sealedP2" });
|
||||
ModuleHelper.DefineModule(m1x, false, "9.0", "m1x/here",
|
||||
new String[] { "sealedP1", "sealedP2" });
|
||||
|
||||
// Define a module for package sealedP3 with the same class loader.
|
||||
m2x = ModuleHelper.ModuleObject("module_two", this_cldr, new String[] { "sealedP3" });
|
||||
ModuleHelper.DefineModule(m2x, false, "9.0", "m2x/there", new String[] { "sealedP3" });
|
||||
|
||||
// Make package sealedP1 in m1x visible to everyone because it contains
|
||||
// the super class for C1, C2, and C3.
|
||||
ModuleHelper.AddModuleExportsToAll(m1x, "sealedP1");
|
||||
ModuleHelper.AddReadsModule(m2x, m1x);
|
||||
|
||||
// Test subtype in the same named package and named module as its super
|
||||
// class. This should succeed.
|
||||
// Class sealedP1.C1 extends class sealedP1.SuperClass.
|
||||
Class p1_C1_class = Class.forName("sealedP1.C1");
|
||||
|
||||
// Test non-public class in same module but different package than its
|
||||
// super class. This should throw ICCE.
|
||||
// Class sealedP2.C2 extends class sealedP1.SuperClass.
|
||||
try {
|
||||
Class p2_C2_class = Class.forName("sealedP2.C2");
|
||||
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
if (!e.getMessage().contains("cannot inherit from sealed class")) {
|
||||
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Test subtype in a different module than its super type. This should
|
||||
// fail even though they have the same class loader.
|
||||
// Class sealedP3.C3 extends class sealedP1.SuperClass.
|
||||
try {
|
||||
Class p3_C3_class = Class.forName("sealedP3.C3");
|
||||
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
if (!e.getMessage().contains("cannot inherit from sealed class")) {
|
||||
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
23
test/hotspot/jtreg/runtime/modules/TEST.properties
Normal file
23
test/hotspot/jtreg/runtime/modules/TEST.properties
Normal file
@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
allowSmartActionArgs=true
|
30
test/hotspot/jtreg/runtime/modules/sealedP1/C1.java
Normal file
30
test/hotspot/jtreg/runtime/modules/sealedP1/C1.java
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// Small class used by SealedModuleTest
|
||||
package sealedP1;
|
||||
|
||||
public final class C1 extends sealedP1.SuperClass {
|
||||
|
||||
public C1() { }
|
||||
}
|
105
test/hotspot/jtreg/runtime/modules/sealedP1/SuperClass.jcod
Normal file
105
test/hotspot/jtreg/runtime/modules/sealedP1/SuperClass.jcod
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// This sealed class cannot be a java file because its permits clause names
|
||||
// a class in another package causing javac to issue a compilation error.
|
||||
//
|
||||
// Sealed super class used by SealedModuleTest.
|
||||
//
|
||||
// package sealedP1;
|
||||
//
|
||||
// public sealed class SuperClass permits sealedP1.C1, sealedP2.C2, sealedP3.C3 { }
|
||||
|
||||
class sealedP1/SuperClass {
|
||||
0xCAFEBABE;
|
||||
65535; // minor version
|
||||
59; // version
|
||||
[20] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "sealedP1/SuperClass"; // #8 at 0x3C
|
||||
Utf8 "Code"; // #9 at 0x52
|
||||
Utf8 "LineNumberTable"; // #10 at 0x59
|
||||
Utf8 "SourceFile"; // #11 at 0x6B
|
||||
Utf8 "SuperClass.java"; // #12 at 0x78
|
||||
Utf8 "PermittedSubclasses"; // #13 at 0x8A
|
||||
class #15; // #14 at 0x9E
|
||||
Utf8 "sealedP1/C1"; // #15 at 0xA1
|
||||
class #17; // #16 at 0xAF
|
||||
Utf8 "sealedP2/C2"; // #17 at 0xB2
|
||||
class #19; // #18 at 0xC0
|
||||
Utf8 "sealedP3/C3"; // #19 at 0xC3
|
||||
} // Constant Pool
|
||||
|
||||
0x0021; // access [ ACC_PUBLIC ACC_SUPER ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xDD
|
||||
0x0001; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0xE5
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
}
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xFC
|
||||
[1] { // LineNumberTable
|
||||
0 28; // at 0x0108
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#11, 2) { // SourceFile at 0x010A
|
||||
#12;
|
||||
} // end SourceFile
|
||||
;
|
||||
Attr(#13, 8) { // PermittedSubclasses at 0x0112
|
||||
0x0003000E00100012;
|
||||
} // end PermittedSubclasses
|
||||
} // Attributes
|
||||
} // end class sealedP1/SuperClass
|
29
test/hotspot/jtreg/runtime/modules/sealedP2/C2.java
Normal file
29
test/hotspot/jtreg/runtime/modules/sealedP2/C2.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// Small class used by SealedModuleTest
|
||||
package sealedP2;
|
||||
|
||||
final class C2 extends sealedP1.SuperClass {
|
||||
public void method2() { }
|
||||
}
|
29
test/hotspot/jtreg/runtime/modules/sealedP3/C3.java
Normal file
29
test/hotspot/jtreg/runtime/modules/sealedP3/C3.java
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// Small class used by SealedModuleTest
|
||||
package sealedP3;
|
||||
|
||||
public final class C3 extends sealedP1.SuperClass {
|
||||
public void method3() { }
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225056
|
||||
* @compile --enable-preview -source ${jdk.version} AbstractSealedTest.java
|
||||
* @run main/othervm --enable-preview AbstractSealedTest
|
||||
*/
|
||||
|
||||
// Test that a sealed class can be abstract
|
||||
public class AbstractSealedTest {
|
||||
|
||||
abstract sealed class AbstractShape permits Circle {
|
||||
abstract void draw();
|
||||
}
|
||||
|
||||
final class Circle extends AbstractShape {
|
||||
void draw() {}
|
||||
}
|
||||
|
||||
Circle circle = new Circle();
|
||||
|
||||
public static void main(String... args) { }
|
||||
}
|
@ -0,0 +1,560 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// This class has entries in its PermittedSubclasses attribute that do not exist.
|
||||
// Test that this does not prevent JVM_GetPermittedSubclasses() from returning
|
||||
// their names.
|
||||
//
|
||||
// sealed class NoLoadSubclasses permits iDontExist, I/Dont/Exist/Either { }
|
||||
//
|
||||
class NoLoadSubclasses {
|
||||
0xCAFEBABE;
|
||||
65535; // minor version
|
||||
59; // version
|
||||
[18] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "NoLoadSubclasses"; // #8 at 0x3C
|
||||
Utf8 "Code"; // #9 at 0x4D
|
||||
Utf8 "LineNumberTable"; // #10 at 0x54
|
||||
Utf8 "SourceFile"; // #11 at 0x66
|
||||
Utf8 "NoLoadSubclasses.java"; // #12 at 0x73
|
||||
Utf8 "PermittedSubclasses"; // #13 at 0x89
|
||||
class #15; // #14 at 0x9D
|
||||
Utf8 "iDontExist"; // #15 at 0xA0
|
||||
class #17; // #16 at 0xAA
|
||||
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
|
||||
} // Constant Pool
|
||||
|
||||
0x0020; // access [ ACC_SUPER ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xC1
|
||||
0x0000; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0xC9
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
}
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xE0
|
||||
[1] { // LineNumberTable
|
||||
0 1; // at 0xEC
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#13, 6) { // PermittedSubclasses at 0xF6
|
||||
0x0002000E0010;
|
||||
} // end PermittedSubclasses
|
||||
;
|
||||
Attr(#11, 2) { // SourceFile at 0xEE
|
||||
#12;
|
||||
} // end SourceFile
|
||||
} // Attributes
|
||||
} // end class NoLoadSubclasses
|
||||
|
||||
|
||||
|
||||
// This class contains an empty PermittedSubclasses attribute. Test that
|
||||
// this causes an exception to get thrown.
|
||||
class NoSubclasses {
|
||||
0xCAFEBABE;
|
||||
65535; // minor version
|
||||
59; // version
|
||||
[14] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "NoSubclasses"; // #8 at 0x3C
|
||||
Utf8 "Code"; // #9 at 0x49
|
||||
Utf8 "LineNumberTable"; // #10 at 0x50
|
||||
Utf8 "SourceFile"; // #11 at 0x62
|
||||
Utf8 "NoSubclasses.java"; // #12 at 0x6F
|
||||
Utf8 "PermittedSubclasses"; // #13 at 0x81
|
||||
} // Constant Pool
|
||||
|
||||
0x0020; // access [ ACC_SUPER ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xAB
|
||||
0x0000; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0xB3
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
}
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xCA
|
||||
[1] { // LineNumberTable
|
||||
0 1; // at 0xD6
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#11, 2) { // SourceFile at 0xD8
|
||||
#12;
|
||||
} // end SourceFile
|
||||
;
|
||||
Attr(#13, 2) { // PermittedSubclasses at 0xE0
|
||||
0x0000;
|
||||
} // end PermittedSubclasses
|
||||
} // Attributes
|
||||
} // end class NoSubclasses
|
||||
|
||||
|
||||
|
||||
// This class has a PermittedSubclasses attribute but an old class file version.
|
||||
// The PermittedSubclasses attribute should be ignored.
|
||||
//
|
||||
// sealed class OldClassFile permits iDontExist, I/Dont/Exist/Either { }
|
||||
//
|
||||
class OldClassFile {
|
||||
0xCAFEBABE;
|
||||
0; // minor version
|
||||
57; // version
|
||||
[18] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "OldClassFile"; // #8 at 0x3C
|
||||
Utf8 "Code"; // #9 at 0x4D
|
||||
Utf8 "LineNumberTable"; // #10 at 0x54
|
||||
Utf8 "SourceFile"; // #11 at 0x66
|
||||
Utf8 "OldClassFile.java"; // #12 at 0x73
|
||||
Utf8 "PermittedSubclasses"; // #13 at 0x89
|
||||
class #15; // #14 at 0x9D
|
||||
Utf8 "iDontExist"; // #15 at 0xA0
|
||||
class #17; // #16 at 0xAA
|
||||
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
|
||||
} // Constant Pool
|
||||
|
||||
0x0030; // access [ ACC_SUPER ACC_FINAL ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xC1
|
||||
0x0000; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0xC9
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
}
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xE0
|
||||
[1] { // LineNumberTable
|
||||
0 1; // at 0xEC
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#11, 2) { // SourceFile at 0xEE
|
||||
#12;
|
||||
} // end SourceFile
|
||||
;
|
||||
Attr(#13, 6) { // PermittedSubclasses at 0xF6
|
||||
0x0002000E0010;
|
||||
} // end PermittedSubclasses
|
||||
} // Attributes
|
||||
} // end class OldClassFile
|
||||
|
||||
|
||||
|
||||
// This class has a corrupted PermittedSubclasses attribute. Attempts to load it
|
||||
// should throw ClassFormatError.
|
||||
class BadPermittedAttr {
|
||||
0xCAFEBABE;
|
||||
65535; // minor version
|
||||
59; // version
|
||||
[18] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "BadPermittedAttr"; // #8 at 0x3C
|
||||
Utf8 "Code"; // #9 at 0x4D
|
||||
Utf8 "LineNumberTable"; // #10 at 0x54
|
||||
Utf8 "SourceFile"; // #11 at 0x66
|
||||
Utf8 "BadPermittedAttr.java"; // #12 at 0x73
|
||||
Utf8 "PermittedSubclasses"; // #13 at 0x89
|
||||
class #15; // #14 at 0x9D
|
||||
Utf8 "iDontExist"; // #15 at 0xA0
|
||||
class #17; // #16 at 0xAA
|
||||
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
|
||||
} // Constant Pool
|
||||
|
||||
0x0020; // access [ ACC_SUPER ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xC1
|
||||
0x0000; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0xC9
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
}
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xE0
|
||||
[1] { // LineNumberTable
|
||||
0 1; // at 0xEC
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#11, 2) { // SourceFile at 0xEE
|
||||
#12;
|
||||
} // end SourceFile
|
||||
;
|
||||
Attr(#13, 6) { // PermittedSubclasses at 0xF6
|
||||
0x0002000F0010;
|
||||
} // end PermittedSubclasses
|
||||
} // Attributes
|
||||
} // end class BadPermittedAttr
|
||||
|
||||
|
||||
// This class has a PermittedSubclasses attribute and is marked Final.
|
||||
// Loading this class should throw a ClassFormatError exception.
|
||||
//
|
||||
// sealed class SealedButFinal permits iDontExist, I/Dont/Exist/Either { }
|
||||
//
|
||||
class SealedButFinal {
|
||||
0xCAFEBABE;
|
||||
65535; // minor version
|
||||
59; // version
|
||||
[18] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "SealedButFinal"; // #8 at 0x3C
|
||||
Utf8 "Code"; // #9 at 0x4D
|
||||
Utf8 "LineNumberTable"; // #10 at 0x54
|
||||
Utf8 "SourceFile"; // #11 at 0x66
|
||||
Utf8 "SealedButFinal.java"; // #12 at 0x73
|
||||
Utf8 "PermittedSubclasses"; // #13 at 0x89
|
||||
class #15; // #14 at 0x9D
|
||||
Utf8 "iDontExist"; // #15 at 0xA0
|
||||
class #17; // #16 at 0xAA
|
||||
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
|
||||
} // Constant Pool
|
||||
|
||||
0x0030; // access [ ACC_SUPER ACC_FINAL ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xC1
|
||||
0x0000; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0xC9
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
}
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xE0
|
||||
[1] { // LineNumberTable
|
||||
0 1; // at 0xEC
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#11, 2) { // SourceFile at 0xEE
|
||||
#12;
|
||||
} // end SourceFile
|
||||
;
|
||||
Attr(#13, 6) { // PermittedSubclasses at 0xF6
|
||||
0x0002000E0010;
|
||||
} // end PermittedSubclasses
|
||||
} // Attributes
|
||||
} // end class SealedButFinal
|
||||
|
||||
|
||||
// This class contains a PermittedSubclasses attribute with an invalid class
|
||||
// name. Test that this causes a ClassFormatError exception to get thrown.
|
||||
//
|
||||
// sealed class BadPermittedSubclassEntry permits iDont;;Exist, I/Dont/Exist/Either { }
|
||||
//
|
||||
class BadPermittedSubclassEntry {
|
||||
0xCAFEBABE;
|
||||
65535; // minor version
|
||||
59; // version
|
||||
[18] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "BadPermittedSubclassEntry"; // #8 at 0x3C
|
||||
Utf8 "Code"; // #9 at 0x4D
|
||||
Utf8 "LineNumberTable"; // #10 at 0x54
|
||||
Utf8 "SourceFile"; // #11 at 0x66
|
||||
Utf8 "BadPermittedSubclassEntry.java"; // #12 at 0x73
|
||||
Utf8 "PermittedSubclasses"; // #13 at 0x89
|
||||
class #15; // #14 at 0x9D
|
||||
Utf8 "iDont;;Exist"; // #15 at 0xA0
|
||||
class #17; // #16 at 0xAA
|
||||
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
|
||||
} // Constant Pool
|
||||
|
||||
0x0020; // access [ ACC_SUPER ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xC1
|
||||
0x0000; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0xC9
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
}
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xE0
|
||||
[1] { // LineNumberTable
|
||||
0 1; // at 0xEC
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#13, 6) { // PermittedSubclasses at 0xF6
|
||||
0x0002000E0010;
|
||||
} // end PermittedSubclasses
|
||||
;
|
||||
Attr(#11, 2) { // SourceFile at 0xEE
|
||||
#12;
|
||||
} // end SourceFile
|
||||
} // Attributes
|
||||
}
|
||||
|
||||
// This class contains a PermittedSubclasses attribute with an empty class
|
||||
// name. Test that this causes a ClassFormatError exception to get thrown.
|
||||
//
|
||||
// sealed class EmptyPermittedSubclassEntry permits "", I/Dont/Exist/Either { }
|
||||
//
|
||||
class EmptyPermittedSubclassEntry {
|
||||
0xCAFEBABE;
|
||||
65535; // minor version
|
||||
59; // version
|
||||
[18] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "EmptyPermittedSubclassEntry"; // #8 at 0x3C
|
||||
Utf8 "Code"; // #9 at 0x4D
|
||||
Utf8 "LineNumberTable"; // #10 at 0x54
|
||||
Utf8 "SourceFile"; // #11 at 0x66
|
||||
Utf8 "EmptyPermittedSubclassEntry.java"; // #12 at 0x73
|
||||
Utf8 "PermittedSubclasses"; // #13 at 0x89
|
||||
class #15; // #14 at 0x9D
|
||||
Utf8 ""; // #15 at 0xA0
|
||||
class #17; // #16 at 0xAA
|
||||
Utf8 "I/Dont/Exist/Either"; // #17 at 0xAD
|
||||
} // Constant Pool
|
||||
|
||||
0x0020; // access [ ACC_SUPER ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xC1
|
||||
0x0000; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0xC9
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
}
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xE0
|
||||
[1] { // LineNumberTable
|
||||
0 1; // at 0xEC
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#13, 6) { // PermittedSubclasses at 0xF6
|
||||
0x0002000E0010;
|
||||
} // end PermittedSubclasses
|
||||
;
|
||||
Attr(#11, 2) { // SourceFile at 0xEE
|
||||
#12;
|
||||
} // end SourceFile
|
||||
} // Attributes
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225056
|
||||
* @compile GetPermittedSubclasses.jcod
|
||||
* @compile --enable-preview -source ${jdk.version} GetPermittedSubclassesTest.java
|
||||
* @run main/othervm --enable-preview GetPermittedSubclassesTest
|
||||
*/
|
||||
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.util.ArrayList;
|
||||
|
||||
// Test Class GetPermittedSubtpes() and Class.isSealed() APIs.
|
||||
public class GetPermittedSubclassesTest {
|
||||
|
||||
sealed class Sealed1 permits Sub1 {}
|
||||
|
||||
final class Sub1 extends Sealed1 implements SealedI1 {}
|
||||
|
||||
sealed interface SealedI1 permits NotSealed, Sub1, Extender {}
|
||||
|
||||
non-sealed interface Extender extends SealedI1 { }
|
||||
|
||||
final class FinalC implements Extender {}
|
||||
|
||||
final class NotSealed implements SealedI1 {}
|
||||
|
||||
final class Final4 {}
|
||||
|
||||
public static void testSealedInfo(Class<?> c, String[] expected) {
|
||||
Object[] permitted = c.permittedSubclasses();
|
||||
|
||||
if (permitted.length != expected.length) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected number of permitted subclasses for: " + c.toString());
|
||||
}
|
||||
|
||||
if (permitted.length > 0) {
|
||||
if (!c.isSealed()) {
|
||||
throw new RuntimeException("Expected sealed class: " + c.toString());
|
||||
}
|
||||
|
||||
// Create ArrayList of permitted subclasses class names.
|
||||
ArrayList<String> permittedNames = new ArrayList<String>();
|
||||
for (int i = 0; i < permitted.length; i++) {
|
||||
permittedNames.add(((ClassDesc)permitted[i]).descriptorString());
|
||||
}
|
||||
|
||||
if (permittedNames.size() != expected.length) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected number of permitted names for: " + c.toString());
|
||||
}
|
||||
|
||||
// Check that expected class names are in the permitted subclasses list.
|
||||
for (int i = 0; i < expected.length; i++) {
|
||||
if (!permittedNames.contains(expected[i])) {
|
||||
throw new RuntimeException(
|
||||
"Expected class not found in permitted subclases list, super class: " +
|
||||
c.getName() + ", expected class: " + expected[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Must not be sealed if no permitted subclasses.
|
||||
if (c.isSealed()) {
|
||||
throw new RuntimeException("Unexpected sealed class: " + c.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void testBadSealedClass(String className, String expectedCFEMessage) throws Throwable {
|
||||
try {
|
||||
Class.forName(className);
|
||||
throw new RuntimeException("Expected ClassFormatError exception not thrown for " + className);
|
||||
} catch (ClassFormatError cfe) {
|
||||
if (!cfe.getMessage().contains(expectedCFEMessage)) {
|
||||
throw new RuntimeException(
|
||||
"Class " + className + " got unexpected ClassFormatError exception: " + cfe.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Throwable {
|
||||
testSealedInfo(SealedI1.class, new String[] {"LGetPermittedSubclassesTest$NotSealed;",
|
||||
"LGetPermittedSubclassesTest$Sub1;",
|
||||
"LGetPermittedSubclassesTest$Extender;"});
|
||||
testSealedInfo(Sealed1.class, new String[] {"LGetPermittedSubclassesTest$Sub1;"});
|
||||
testSealedInfo(Final4.class, new String[] { });
|
||||
testSealedInfo(NotSealed.class, new String[] { });
|
||||
|
||||
// Test class with PermittedSubclasses attribute but old class file version.
|
||||
testSealedInfo(OldClassFile.class, new String[] { });
|
||||
|
||||
// Test class with an empty PermittedSubclasses attribute.
|
||||
testBadSealedClass("NoSubclasses", "PermittedSubclasses attribute is empty");
|
||||
|
||||
// Test returning names of non-existing classes.
|
||||
testSealedInfo(NoLoadSubclasses.class, new String[]{"LiDontExist;", "LI/Dont/Exist/Either;"});
|
||||
|
||||
// Test that loading a class with a corrupted PermittedSubclasses attribute
|
||||
// causes a ClassFormatError.
|
||||
testBadSealedClass("BadPermittedAttr",
|
||||
"Permitted subclass class_info_index 15 has bad constant type");
|
||||
|
||||
// Test that loading a sealed final class with a PermittedSubclasses
|
||||
// attribute causes a ClassFormatError.
|
||||
testBadSealedClass("SealedButFinal", "PermittedSubclasses attribute in final class");
|
||||
|
||||
// Test that loading a sealed class with a bad class name in its PermittedSubclasses
|
||||
// attribute causes a ClassFormatError.
|
||||
testBadSealedClass("BadPermittedSubclassEntry", "Illegal class name \"iDont;;Exist\" in class file");
|
||||
|
||||
// Test that loading a sealed class with an empty class name in its PermittedSubclasses
|
||||
// attribute causes a ClassFormatError.
|
||||
testBadSealedClass("EmptyPermittedSubclassEntry", "Illegal class name \"\" in class file");
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225056
|
||||
* @compile --enable-preview -source ${jdk.version} OverrideSealedTest.java
|
||||
* @run main/othervm --enable-preview OverrideSealedTest
|
||||
*/
|
||||
|
||||
// Test that a method in a sealed class or interface can be overridden.
|
||||
public class OverrideSealedTest {
|
||||
|
||||
sealed class Rectangle permits Square {
|
||||
public String draw() { return "rectangle"; }
|
||||
}
|
||||
|
||||
final class Square extends Rectangle {
|
||||
public String draw() { return "square"; }
|
||||
}
|
||||
|
||||
Rectangle r = new Rectangle();
|
||||
Rectangle rs = new Square();
|
||||
Square s = new Square();
|
||||
|
||||
|
||||
public sealed interface Shape permits Circle {
|
||||
default String name() { return "shape"; }
|
||||
}
|
||||
|
||||
final class Circle implements Shape {
|
||||
public String name() { return "circle"; }
|
||||
}
|
||||
|
||||
Shape sc = new Circle();
|
||||
Circle c = new Circle();
|
||||
|
||||
|
||||
public static void main(String... args) {
|
||||
OverrideSealedTest ost = new OverrideSealedTest();
|
||||
if (ost.r.draw() != "rectangle")
|
||||
throw new RuntimeException("Bad value returned by draw(): " + ost.r.draw());
|
||||
if (ost.rs.draw() != "square")
|
||||
throw new RuntimeException("Bad value returned by draw(): " + ost.rs.draw());
|
||||
if (ost.s.draw() != "square")
|
||||
throw new RuntimeException("Bad value returned by draw(): " + ost.s.draw());
|
||||
|
||||
if (ost.sc.name() != "circle")
|
||||
throw new RuntimeException("Bad value returned by name(): " + ost.sc.name());
|
||||
if (ost.c.name() != "circle")
|
||||
throw new RuntimeException("Bad value returned by name(): " + ost.c.name());
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// This class was written using jcod because it implements sealed interface
|
||||
// SealedInterface but is not listed in its PermittedSubclasses attribute.
|
||||
// It consists of the following:
|
||||
//
|
||||
// package Pkg;
|
||||
// public class NotPermitted implements SealedInterface { }
|
||||
//
|
||||
class Pkg/NotPermitted {
|
||||
0xCAFEBABE;
|
||||
0; // minor version
|
||||
59; // version
|
||||
[15] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "Pkg/NotPermitted"; // #8 at 0x3C
|
||||
class #10; // #9 at 0x4C
|
||||
Utf8 "Pkg/SealedInterface"; // #10 at 0x4F
|
||||
Utf8 "Code"; // #11 at 0x65
|
||||
Utf8 "LineNumberTable"; // #12 at 0x6C
|
||||
Utf8 "SourceFile"; // #13 at 0x7E
|
||||
Utf8 "NotPermitted.java"; // #14 at 0x8B
|
||||
} // Constant Pool
|
||||
|
||||
0x0031; // access [ ACC_PUBLIC ACC_SUPER ACC_FINAL ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[1] { // Interfaces
|
||||
#9;
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xAA
|
||||
0x0001; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#11, 29) { // Code at 0xB2
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
};
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#12, 6) { // LineNumberTable at 0xC9
|
||||
[1] { // LineNumberTable
|
||||
0 26; // at 0xD5
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[1] { // Attributes
|
||||
Attr(#13, 2) { // SourceFile at 0xD7
|
||||
#14;
|
||||
} // end SourceFile
|
||||
} // Attributes
|
||||
} // end class Pkg/NotPermitted
|
26
test/hotspot/jtreg/runtime/sealedClasses/Pkg/Permitted.java
Normal file
26
test/hotspot/jtreg/runtime/sealedClasses/Pkg/Permitted.java
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package Pkg;
|
||||
|
||||
final class Permitted implements SealedInterface { }
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// This sealed class cannot be a java file because its permits clause names
|
||||
// a class in another package causing javac to issue a compilation error.
|
||||
//
|
||||
// package Pkg;
|
||||
//
|
||||
// sealed public interface SealedInterface permits Permitted, otherPkg.WrongPackage { }
|
||||
|
||||
class Pkg/SealedInterface {
|
||||
0xCAFEBABE;
|
||||
65535; // minor version
|
||||
59; // version
|
||||
[12] { // Constant Pool
|
||||
; // first element is empty
|
||||
class #2; // #1 at 0x0A
|
||||
Utf8 "Pkg/SealedInterface"; // #2 at 0x0D
|
||||
class #4; // #3 at 0x23
|
||||
Utf8 "java/lang/Object"; // #4 at 0x26
|
||||
Utf8 "SourceFile"; // #5 at 0x39
|
||||
Utf8 "SealedInterface.java"; // #6 at 0x46
|
||||
Utf8 "PermittedSubclasses"; // #7 at 0x5D
|
||||
class #9; // #8 at 0x71
|
||||
Utf8 "Pkg/Permitted"; // #9 at 0x74
|
||||
class #11; // #10 at 0x84
|
||||
Utf8 "otherPkg/WrongPackage"; // #11 at 0x87
|
||||
} // Constant Pool
|
||||
|
||||
0x0601; // access [ ACC_PUBLIC ACC_INTERFACE ]
|
||||
#1;// this_cpx
|
||||
#3;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[0] { // methods
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#5, 2) { // SourceFile at 0xAD
|
||||
#6;
|
||||
} // end SourceFile
|
||||
;
|
||||
Attr(#7, 6) { // PermittedSubtclasses at 0xB5
|
||||
0x00020008000A;
|
||||
} // end PermittedSubclasses
|
||||
} // Attributes
|
||||
} // end class Pkg/SealedInterface
|
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225056
|
||||
* @library /test/lib
|
||||
* @summary Test that a class that is a sealed class can be redefined.
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @modules java.instrument
|
||||
* jdk.jartool/sun.tools.jar
|
||||
* @compile --enable-preview -source ${jdk.version} RedefineSealedClass.java
|
||||
* @run main/othervm --enable-preview RedefineSealedClass buildagent
|
||||
* @run main/othervm/timeout=6000 --enable-preview RedefineSealedClass runtest
|
||||
*/
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.RuntimeException;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class RedefineSealedClass {
|
||||
|
||||
final class A extends Tester { }
|
||||
final class B extends Tester { }
|
||||
|
||||
sealed static class Tester permits A, B {}
|
||||
|
||||
static class LoggingTransformer implements ClassFileTransformer {
|
||||
|
||||
public LoggingTransformer() {}
|
||||
|
||||
public byte[] transform(ClassLoader loader, String className,
|
||||
Class classBeingRedefined, ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer) throws IllegalClassFormatException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void premain(String agentArgs, Instrumentation inst) throws Exception {
|
||||
LoggingTransformer t = new LoggingTransformer();
|
||||
inst.addTransformer(t, true);
|
||||
{
|
||||
Class demoClass = Class.forName("RedefineSealedClass$Tester");
|
||||
inst.retransformClasses(demoClass);
|
||||
}
|
||||
}
|
||||
|
||||
private static void buildAgent() {
|
||||
try {
|
||||
ClassFileInstaller.main("RedefineSealedClass");
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Could not write agent classfile", e);
|
||||
}
|
||||
|
||||
try {
|
||||
PrintWriter pw = new PrintWriter("MANIFEST.MF");
|
||||
pw.println("Premain-Class: RedefineSealedClass");
|
||||
pw.println("Agent-Class: RedefineSealedClass");
|
||||
pw.println("Can-Redefine-Classes: true");
|
||||
pw.println("Can-Retransform-Classes: true");
|
||||
pw.close();
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException("Could not write manifest file for the agent", e);
|
||||
}
|
||||
|
||||
sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
|
||||
if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineSealedClass.class" })) {
|
||||
throw new RuntimeException("Could not write the agent jar file");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String argv[]) throws Exception {
|
||||
if (argv.length == 1 && argv[0].equals("buildagent")) {
|
||||
buildAgent();
|
||||
return;
|
||||
}
|
||||
if (argv.length == 1 && argv[0].equals("runtest")) {
|
||||
String[] javaArgs1 = { "-XX:MetaspaceSize=12m", "-XX:MaxMetaspaceSize=12m",
|
||||
"-javaagent:redefineagent.jar", "--enable-preview",
|
||||
"RedefineSealedClass"};
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(javaArgs1);
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldNotContain("processing of -javaagent failed");
|
||||
}
|
||||
}
|
||||
}
|
49
test/hotspot/jtreg/runtime/sealedClasses/SealedTest.java
Normal file
49
test/hotspot/jtreg/runtime/sealedClasses/SealedTest.java
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225056
|
||||
* @compile --enable-preview -source ${jdk.version} SealedTest.java
|
||||
* @run main/othervm --enable-preview SealedTest
|
||||
*/
|
||||
|
||||
public class SealedTest {
|
||||
|
||||
sealed class Sealed1 permits Sub1 {}
|
||||
|
||||
final class Sub1 extends Sealed1 {}
|
||||
|
||||
sealed interface SealedI1 permits Sub2 {}
|
||||
|
||||
final class Sub2 extends Sealed2 implements SealedI1 {}
|
||||
|
||||
sealed class Sealed2 permits Sub2 {}
|
||||
|
||||
Sub1 sub1 = new Sub1();
|
||||
Sub2 sub2 = new Sub2();
|
||||
|
||||
public static void main(String... args) {
|
||||
System.out.println("Basic testing of sealed types");
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225056
|
||||
* @compile Pkg/SealedInterface.jcod Pkg/NotPermitted.jcod
|
||||
* @compile --enable-preview -source ${jdk.version} Pkg/Permitted.java otherPkg/WrongPackage.java
|
||||
* @run main/othervm --enable-preview SealedUnnamedModuleIntfTest
|
||||
*/
|
||||
|
||||
public class SealedUnnamedModuleIntfTest {
|
||||
|
||||
public static void main(String args[]) throws Throwable {
|
||||
|
||||
// Classes Permitted, NotPermitted, and WrongPackage all try to implement
|
||||
// sealed interface SealedInterface.
|
||||
// Interface SealedInterface permits classes Permitted and WrongPackage.
|
||||
|
||||
// Test non-public permitted subclass and superclass in unnamed module and
|
||||
// same package. This should succeed.
|
||||
Class permitted = Class.forName("Pkg.Permitted");
|
||||
|
||||
// Test unpermitted subclass and superclass in unnamed module and same package.
|
||||
// This should throw an exception.
|
||||
try {
|
||||
Class notPermitted = Class.forName("Pkg.NotPermitted");
|
||||
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
if (!e.getMessage().contains("cannot implement sealed interface")) {
|
||||
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Test public permitted subclass and superclass in same unnamed module but in
|
||||
// different packages. This should not throw an exception.
|
||||
Class wrongPkg = Class.forName("otherPkg.WrongPackage");
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8225056
|
||||
* @compile planets/OuterPlanets.jcod planets/Mars.jcod
|
||||
* @compile --enable-preview -source ${jdk.version} planets/Neptune.java asteroids/Pluto.java
|
||||
* @run main/othervm --enable-preview SealedUnnamedModuleTest
|
||||
*/
|
||||
|
||||
public class SealedUnnamedModuleTest {
|
||||
|
||||
public static void main(String args[]) throws Throwable {
|
||||
|
||||
// Classes Neptune, Mars, and Pluto all try to extend sealed class OuterPlanets.
|
||||
// Class OuterPlanets permits Nepturn and Pluto.
|
||||
|
||||
// Test permitted subclass and superclass in unnamed module and same package.
|
||||
// This should succeed.
|
||||
Class neptune = Class.forName("planets.Neptune");
|
||||
|
||||
// Test unpermitted subclass and superclass in unnamed module and same package.
|
||||
// This should fail.
|
||||
try {
|
||||
Class mars = Class.forName("planets.Mars");
|
||||
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
if (!e.getMessage().contains("cannot inherit from sealed class")) {
|
||||
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Test non-public permitted subclass and superclass in same unnamed module but
|
||||
// in different packages. This should fail.
|
||||
try {
|
||||
Class pluto = Class.forName("asteroids.Pluto");
|
||||
throw new RuntimeException("Expected IncompatibleClassChangeError exception not thrown");
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
if (!e.getMessage().contains("cannot inherit from sealed class")) {
|
||||
throw new RuntimeException("Wrong IncompatibleClassChangeError exception thrown: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
test/hotspot/jtreg/runtime/sealedClasses/TEST.properties
Normal file
23
test/hotspot/jtreg/runtime/sealedClasses/TEST.properties
Normal file
@ -0,0 +1,23 @@
|
||||
#
|
||||
# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
allowSmartActionArgs=true
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package asteroids;
|
||||
|
||||
final class Pluto extends planets.OuterPlanets { }
|
||||
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package otherPkg;
|
||||
|
||||
public final class WrongPackage implements Pkg.SealedInterface { }
|
92
test/hotspot/jtreg/runtime/sealedClasses/planets/Mars.jcod
Normal file
92
test/hotspot/jtreg/runtime/sealedClasses/planets/Mars.jcod
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// This class was written using jcod because it extends sealed class
|
||||
// planets.OuterPlanets but is not listed in its PermittedSubclasses
|
||||
// attribute. It consists of the following:
|
||||
//
|
||||
// package planets;
|
||||
// public class Mars extends OuterPlanets { }
|
||||
//
|
||||
class planets/Mars {
|
||||
0xCAFEBABE;
|
||||
0; // minor version
|
||||
59; // version
|
||||
[13] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "planets/OuterPlanets"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2E
|
||||
Utf8 "()V"; // #6 at 0x37
|
||||
class #8; // #7 at 0x3D
|
||||
Utf8 "planets/Mars"; // #8 at 0x40
|
||||
Utf8 "Code"; // #9 at 0x52
|
||||
Utf8 "LineNumberTable"; // #10 at 0x59
|
||||
Utf8 "SourceFile"; // #11 at 0x6B
|
||||
Utf8 "Mars.java"; // #12 at 0x78
|
||||
} // Constant Pool
|
||||
|
||||
0x0031; // access [ ACC_PUBLIC ACC_SUPER ACC_FINAL ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0x93
|
||||
0x0001; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0x9B
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
};
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xB2
|
||||
[1] { // LineNumberTable
|
||||
0 3; // at 0xBE
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[1] { // Attributes
|
||||
Attr(#11, 2) { // SourceFile at 0xC0
|
||||
#12;
|
||||
} // end SourceFile
|
||||
} // Attributes
|
||||
} // end class planets/Mars
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package planets;
|
||||
|
||||
public final class Neptune extends OuterPlanets { }
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// package planets;
|
||||
//
|
||||
// sealed public class OuterPlanets permits Neptune, asteroids.Pluto { }
|
||||
|
||||
class planets/OuterPlanets {
|
||||
0xCAFEBABE;
|
||||
65535; // minor version
|
||||
59; // version
|
||||
[18] { // Constant Pool
|
||||
; // first element is empty
|
||||
Method #2 #3; // #1 at 0x0A
|
||||
class #4; // #2 at 0x0F
|
||||
NameAndType #5 #6; // #3 at 0x12
|
||||
Utf8 "java/lang/Object"; // #4 at 0x17
|
||||
Utf8 "<init>"; // #5 at 0x2A
|
||||
Utf8 "()V"; // #6 at 0x33
|
||||
class #8; // #7 at 0x39
|
||||
Utf8 "planets/OuterPlanets"; // #8 at 0x3C
|
||||
Utf8 "Code"; // #9 at 0x53
|
||||
Utf8 "LineNumberTable"; // #10 at 0x5A
|
||||
Utf8 "SourceFile"; // #11 at 0x6C
|
||||
Utf8 "OuterPlanets.java"; // #12 at 0x79
|
||||
Utf8 "PermittedSubclasses"; // #13 at 0x8D
|
||||
class #15; // #14 at 0xA1
|
||||
Utf8 "planets/Neptune"; // #15 at 0xA4
|
||||
class #17; // #16 at 0xB6
|
||||
Utf8 "asteroids/Pluto"; // #17 at 0xB9
|
||||
} // Constant Pool
|
||||
|
||||
0x0021; // access [ ACC_PUBLIC ACC_SUPER ]
|
||||
#7;// this_cpx
|
||||
#2;// super_cpx
|
||||
|
||||
[0] { // Interfaces
|
||||
} // Interfaces
|
||||
|
||||
[0] { // fields
|
||||
} // fields
|
||||
|
||||
[1] { // methods
|
||||
{ // Member at 0xD7
|
||||
0x0001; // access
|
||||
#5; // name_cpx
|
||||
#6; // sig_cpx
|
||||
[1] { // Attributes
|
||||
Attr(#9, 29) { // Code at 0xDF
|
||||
1; // max_stack
|
||||
1; // max_locals
|
||||
Bytes[5]{
|
||||
0x2AB70001B1;
|
||||
}
|
||||
[0] { // Traps
|
||||
} // end Traps
|
||||
[1] { // Attributes
|
||||
Attr(#10, 6) { // LineNumberTable at 0xF6
|
||||
[1] { // LineNumberTable
|
||||
0 26; // at 0x0102
|
||||
}
|
||||
} // end LineNumberTable
|
||||
} // Attributes
|
||||
} // end Code
|
||||
} // Attributes
|
||||
} // Member
|
||||
} // methods
|
||||
|
||||
[2] { // Attributes
|
||||
Attr(#11, 2) { // SourceFile at 0x0104
|
||||
#12;
|
||||
} // end SourceFile
|
||||
;
|
||||
Attr(#13, 6) { // PermittedSubclasses at 0x010C
|
||||
0x0002000E0010;
|
||||
} // end PermittedSubclasses
|
||||
} // Attributes
|
||||
} // end class planets/OuterPlanets
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
final public class ClassFour extends Host { }
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
final public class ClassOne extends Host { }
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
final public class ClassThree extends Host { }
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
final public class ClassTwo extends Host { }
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public class Host {
|
||||
public static String getID() { return "Host/Host.java";}
|
||||
public int m() {
|
||||
return 1; // original class
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public class Host {
|
||||
public static String getID() { return "Host/redef/Host.java";}
|
||||
public int m() {
|
||||
return 2; // redefined class
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public sealed class Host permits ClassOne {
|
||||
public static String getID() { return "HostA/Host.java";}
|
||||
public int m() {
|
||||
return 1; // original class
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public sealed class Host permits ClassOne {
|
||||
public static String getID() { return "HostA/redef/Host.java"; }
|
||||
public int m() {
|
||||
return 2; // redefined class
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public sealed class Host permits ClassOne,ClassTwo {
|
||||
public static String getID() { return "HostAB/Host.java";}
|
||||
public int m() {
|
||||
return 1; // original class
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
public sealed class Host permits ClassOne,ClassTwo {
|
||||
public static String getID() { return "HostAB/redef/Host.java"; }
|
||||
public int m() {
|
||||
return 2; // redefined class
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user