8225054: Compiler implementation for records
8225052: javax.lang.model support for records 8225053: Preview APIs support for records 8225055: Javadoc for records 8226314: com.sun.source support for records 8227113: Specification for java.lang.Record 8233526: JVM support for records Implement records in the compiler and the JVM, including serialization, reflection and APIs support Co-authored-by: Brian Goetz <brian.goetz@oracle.com> Co-authored-by: Maurizio Cimadamore <maurizio.cimadamore@oracle.com> Co-authored-by: Harold Seigel <harold.seigel@oracle.com> Co-authored-by: Joe Darcy <joe.darcy@oracle.com> Co-authored-by: Jonathan Gibbons <jonathan.gibbons@oracle.com> Co-authored-by: Chris Hegarty <chris.hegarty@oracle.com> Co-authored-by: Jan Lahoda <jan.lahoda@oracle.com> Reviewed-by: mcimadamore, briangoetz, alanb, darcy, chegar, jrose, jlahoda, coleenp, dholmes, lfoltan, mchung, sadayapalam, hannesw, sspitsyn
This commit is contained in:
parent
0a375cfa2d
commit
827e5e3226
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2014, 2019, 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
|
||||
@ -80,6 +80,7 @@ define SetupInterimModule
|
||||
ADD_JAVAC_FLAGS := --module-path $(BUILDTOOLS_OUTPUTDIR)/interim_langtools_modules \
|
||||
$$(INTERIM_LANGTOOLS_ADD_EXPORTS) \
|
||||
--patch-module java.base=$(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim \
|
||||
--add-exports java.base/jdk.internal=java.compiler.interim \
|
||||
--add-exports java.base/jdk.internal=jdk.compiler.interim \
|
||||
-Xlint:-module, \
|
||||
))
|
||||
|
@ -122,6 +122,7 @@ JVM_GetNestMembers
|
||||
JVM_GetPrimitiveArrayElement
|
||||
JVM_GetProperties
|
||||
JVM_GetProtectionDomain
|
||||
JVM_GetRecordComponents
|
||||
JVM_GetSimpleBinaryName
|
||||
JVM_GetStackAccessControlContext
|
||||
JVM_GetSystemPackage
|
||||
@ -143,6 +144,7 @@ JVM_IsArrayClass
|
||||
JVM_IsConstructorIx
|
||||
JVM_IsInterface
|
||||
JVM_IsPrimitiveClass
|
||||
JVM_IsRecord
|
||||
JVM_IsSameClassPackage
|
||||
JVM_IsSupportedJNIVersion
|
||||
JVM_IsThreadAlive
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "oops/metadata.hpp"
|
||||
#include "oops/method.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/recordComponent.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "prims/jvmtiThreadState.hpp"
|
||||
@ -3211,6 +3212,173 @@ u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream
|
||||
return length;
|
||||
}
|
||||
|
||||
// Record {
|
||||
// u2 attribute_name_index;
|
||||
// u4 attribute_length;
|
||||
// u2 components_count;
|
||||
// component_info components[components_count];
|
||||
// }
|
||||
// component_info {
|
||||
// u2 name_index;
|
||||
// u2 descriptor_index
|
||||
// u2 attributes_count;
|
||||
// attribute_info_attributes[attributes_count];
|
||||
// }
|
||||
u2 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* const cfs,
|
||||
const ConstantPool* cp,
|
||||
const u1* const record_attribute_start,
|
||||
TRAPS) {
|
||||
const u1* const current_mark = cfs->current();
|
||||
int components_count = 0;
|
||||
unsigned int calculate_attr_size = 0;
|
||||
if (record_attribute_start != NULL) {
|
||||
cfs->set_current(record_attribute_start);
|
||||
cfs->guarantee_more(2, CHECK_0); // num of components
|
||||
components_count = (int)cfs->get_u2_fast();
|
||||
calculate_attr_size = 2;
|
||||
}
|
||||
|
||||
Array<RecordComponent*>* const record_components =
|
||||
MetadataFactory::new_array<RecordComponent*>(_loader_data, components_count, NULL, CHECK_0);
|
||||
_record_components = record_components;
|
||||
|
||||
for (int x = 0; x < components_count; x++) {
|
||||
cfs->guarantee_more(6, CHECK_0); // name_index, descriptor_index, attributes_count
|
||||
|
||||
const u2 name_index = cfs->get_u2_fast();
|
||||
check_property(valid_symbol_at(name_index),
|
||||
"Invalid constant pool index %u for name in Record attribute in class file %s",
|
||||
name_index, CHECK_0);
|
||||
const Symbol* const name = cp->symbol_at(name_index);
|
||||
verify_legal_field_name(name, CHECK_0);
|
||||
|
||||
const u2 descriptor_index = cfs->get_u2_fast();
|
||||
check_property(valid_symbol_at(descriptor_index),
|
||||
"Invalid constant pool index %u for descriptor in Record attribute in class file %s",
|
||||
descriptor_index, CHECK_0);
|
||||
const Symbol* const descr = cp->symbol_at(descriptor_index);
|
||||
verify_legal_field_signature(name, descr, CHECK_0);
|
||||
|
||||
const u2 attributes_count = cfs->get_u2_fast();
|
||||
calculate_attr_size += 6;
|
||||
u2 generic_sig_index = 0;
|
||||
const u1* runtime_visible_annotations = NULL;
|
||||
int runtime_visible_annotations_length = 0;
|
||||
const u1* runtime_invisible_annotations = NULL;
|
||||
int runtime_invisible_annotations_length = 0;
|
||||
bool runtime_invisible_annotations_exists = false;
|
||||
const u1* runtime_visible_type_annotations = NULL;
|
||||
int runtime_visible_type_annotations_length = 0;
|
||||
const u1* runtime_invisible_type_annotations = NULL;
|
||||
int runtime_invisible_type_annotations_length = 0;
|
||||
bool runtime_invisible_type_annotations_exists = false;
|
||||
|
||||
// Expected attributes for record components are Signature, Runtime(In)VisibleAnnotations,
|
||||
// and Runtime(In)VisibleTypeAnnotations. Other attributes are ignored.
|
||||
for (int y = 0; y < attributes_count; y++) {
|
||||
cfs->guarantee_more(6, CHECK_0); // attribute_name_index, attribute_length
|
||||
const u2 attribute_name_index = cfs->get_u2_fast();
|
||||
const u4 attribute_length = cfs->get_u4_fast();
|
||||
calculate_attr_size += 6;
|
||||
check_property(
|
||||
valid_symbol_at(attribute_name_index),
|
||||
"Invalid Record attribute name index %u in class file %s",
|
||||
attribute_name_index, CHECK_0);
|
||||
|
||||
const Symbol* const attribute_name = cp->symbol_at(attribute_name_index);
|
||||
if (attribute_name == vmSymbols::tag_signature()) {
|
||||
if (generic_sig_index != 0) {
|
||||
classfile_parse_error(
|
||||
"Multiple Signature attributes for Record component in class file %s",
|
||||
CHECK_0);
|
||||
}
|
||||
if (attribute_length != 2) {
|
||||
classfile_parse_error(
|
||||
"Invalid Signature attribute length %u in Record component in class file %s",
|
||||
attribute_length, CHECK_0);
|
||||
}
|
||||
generic_sig_index = parse_generic_signature_attribute(cfs, CHECK_0);
|
||||
|
||||
} else if (attribute_name == vmSymbols::tag_runtime_visible_annotations()) {
|
||||
if (runtime_visible_annotations != NULL) {
|
||||
classfile_parse_error(
|
||||
"Multiple RuntimeVisibleAnnotations attributes for Record component in class file %s", CHECK_0);
|
||||
}
|
||||
runtime_visible_annotations_length = attribute_length;
|
||||
runtime_visible_annotations = cfs->current();
|
||||
|
||||
assert(runtime_visible_annotations != NULL, "null record component visible annotation");
|
||||
cfs->guarantee_more(runtime_visible_annotations_length, CHECK_0);
|
||||
cfs->skip_u1_fast(runtime_visible_annotations_length);
|
||||
|
||||
} else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
|
||||
if (runtime_invisible_annotations_exists) {
|
||||
classfile_parse_error(
|
||||
"Multiple RuntimeInvisibleAnnotations attributes for Record component in class file %s", CHECK_0);
|
||||
}
|
||||
runtime_invisible_annotations_exists = true;
|
||||
if (PreserveAllAnnotations) {
|
||||
runtime_invisible_annotations_length = attribute_length;
|
||||
runtime_invisible_annotations = cfs->current();
|
||||
assert(runtime_invisible_annotations != NULL, "null record component invisible annotation");
|
||||
}
|
||||
cfs->skip_u1(attribute_length, CHECK_0);
|
||||
|
||||
} else if (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
|
||||
if (runtime_visible_type_annotations != NULL) {
|
||||
classfile_parse_error(
|
||||
"Multiple RuntimeVisibleTypeAnnotations attributes for Record component in class file %s", CHECK_0);
|
||||
}
|
||||
runtime_visible_type_annotations_length = attribute_length;
|
||||
runtime_visible_type_annotations = cfs->current();
|
||||
|
||||
assert(runtime_visible_type_annotations != NULL, "null record component visible type annotation");
|
||||
cfs->guarantee_more(runtime_visible_type_annotations_length, CHECK_0);
|
||||
cfs->skip_u1_fast(runtime_visible_type_annotations_length);
|
||||
|
||||
} else if (attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
|
||||
if (runtime_invisible_type_annotations_exists) {
|
||||
classfile_parse_error(
|
||||
"Multiple RuntimeInvisibleTypeAnnotations attributes for Record component in class file %s", CHECK_0);
|
||||
}
|
||||
runtime_invisible_type_annotations_exists = true;
|
||||
if (PreserveAllAnnotations) {
|
||||
runtime_invisible_type_annotations_length = attribute_length;
|
||||
runtime_invisible_type_annotations = cfs->current();
|
||||
assert(runtime_invisible_type_annotations != NULL, "null record component invisible type annotation");
|
||||
}
|
||||
cfs->skip_u1(attribute_length, CHECK_0);
|
||||
|
||||
} else {
|
||||
// Skip unknown attributes
|
||||
cfs->skip_u1(attribute_length, CHECK_0);
|
||||
}
|
||||
calculate_attr_size += attribute_length;
|
||||
} // End of attributes For loop
|
||||
|
||||
AnnotationArray* annotations = assemble_annotations(runtime_visible_annotations,
|
||||
runtime_visible_annotations_length,
|
||||
runtime_invisible_annotations,
|
||||
runtime_invisible_annotations_length,
|
||||
CHECK_0);
|
||||
AnnotationArray* type_annotations = assemble_annotations(runtime_visible_type_annotations,
|
||||
runtime_visible_type_annotations_length,
|
||||
runtime_invisible_type_annotations,
|
||||
runtime_invisible_type_annotations_length,
|
||||
CHECK_0);
|
||||
|
||||
RecordComponent* record_component =
|
||||
RecordComponent::allocate(_loader_data, name_index, descriptor_index,
|
||||
attributes_count, generic_sig_index,
|
||||
annotations, type_annotations, CHECK_0);
|
||||
record_components->at_put(x, record_component);
|
||||
} // End of component processing loop
|
||||
|
||||
// Restore buffer's current position.
|
||||
cfs->set_current(current_mark);
|
||||
return calculate_attr_size;
|
||||
}
|
||||
|
||||
void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) {
|
||||
set_class_synthetic_flag(true);
|
||||
}
|
||||
@ -3308,6 +3476,12 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
|
||||
CHECK);
|
||||
}
|
||||
|
||||
bool ClassFileParser::supports_records() {
|
||||
return _major_version == JAVA_14_VERSION &&
|
||||
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
|
||||
Arguments::enable_preview();
|
||||
}
|
||||
|
||||
void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
|
||||
ConstantPool* cp,
|
||||
ClassFileParser::ClassAnnotationCollector* parsed_annotations,
|
||||
@ -3326,6 +3500,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
bool parsed_innerclasses_attribute = false;
|
||||
bool parsed_nest_members_attribute = false;
|
||||
bool parsed_nest_host_attribute = false;
|
||||
bool parsed_record_attribute = false;
|
||||
bool parsed_enclosingmethod_attribute = false;
|
||||
bool parsed_bootstrap_methods_attribute = false;
|
||||
const u1* runtime_visible_annotations = NULL;
|
||||
@ -3345,6 +3520,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
u2 enclosing_method_method_index = 0;
|
||||
const u1* nest_members_attribute_start = NULL;
|
||||
u4 nest_members_attribute_length = 0;
|
||||
const u1* record_attribute_start = NULL;
|
||||
u4 record_attribute_length = 0;
|
||||
|
||||
// Iterate over attributes
|
||||
while (attributes_count--) {
|
||||
@ -3527,6 +3704,38 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
"Nest-host class_info_index %u has bad constant type in class file %s",
|
||||
class_info_index, CHECK);
|
||||
_nest_host = class_info_index;
|
||||
} else if (_major_version >= JAVA_14_VERSION) {
|
||||
if (tag == vmSymbols::tag_record()) {
|
||||
// Skip over Record attribute if not supported or if super class is
|
||||
// not java.lang.Record.
|
||||
if (supports_records() &&
|
||||
cp->klass_name_at(_super_class_index) == vmSymbols::java_lang_Record()) {
|
||||
if (parsed_record_attribute) {
|
||||
classfile_parse_error("Multiple Record attributes in class file %s", CHECK);
|
||||
}
|
||||
// Check that class is final and not abstract.
|
||||
if (!_access_flags.is_final() || _access_flags.is_abstract()) {
|
||||
classfile_parse_error("Record attribute in non-final or abstract class file %s", CHECK);
|
||||
}
|
||||
parsed_record_attribute = true;
|
||||
record_attribute_start = cfs->current();
|
||||
record_attribute_length = attribute_length;
|
||||
} else if (log_is_enabled(Info, class, record)) {
|
||||
// Log why the Record attribute was ignored. Note that if the
|
||||
// class file version is 58.65535 and --enable-preview wasn't
|
||||
// specified then a java.lang.UnsupportedClassVersionError
|
||||
// exception would have been thrown.
|
||||
ResourceMark rm(THREAD);
|
||||
log_info(class, record)("Ignoring Record attribute in class %s because %s",
|
||||
_class_name->as_C_string(),
|
||||
supports_records() ? "super type is not java.lang.Record" :
|
||||
"class file version is not 58.65535");
|
||||
}
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
} else {
|
||||
// Unknown attribute
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
}
|
||||
} else {
|
||||
// Unknown attribute
|
||||
cfs->skip_u1(attribute_length, CHECK);
|
||||
@ -3578,6 +3787,19 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed_record_attribute) {
|
||||
const unsigned int calculated_attr_length = parse_classfile_record_attribute(
|
||||
cfs,
|
||||
cp,
|
||||
record_attribute_start,
|
||||
CHECK);
|
||||
if (_need_verify) {
|
||||
guarantee_property(record_attribute_length == calculated_attr_length,
|
||||
"Record attribute has wrong 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);
|
||||
@ -3632,7 +3854,8 @@ void ClassFileParser::create_combined_annotations(TRAPS) {
|
||||
// Transfer ownership of metadata allocated to the InstanceKlass.
|
||||
void ClassFileParser::apply_parsed_class_metadata(
|
||||
InstanceKlass* this_klass,
|
||||
int java_fields_count, TRAPS) {
|
||||
int java_fields_count,
|
||||
TRAPS) {
|
||||
assert(this_klass != NULL, "invariant");
|
||||
|
||||
_cp->set_pool_holder(this_klass);
|
||||
@ -3644,6 +3867,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_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
|
||||
// its _super. If an OOM occurs while loading the current klass, its _super field
|
||||
@ -4514,6 +4738,7 @@ static Array<InstanceKlass*>* compute_transitive_interfaces(const InstanceKlass*
|
||||
static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
|
||||
assert(this_klass != NULL, "invariant");
|
||||
const Klass* const super = this_klass->super();
|
||||
|
||||
if (super != NULL) {
|
||||
|
||||
// If the loader is not the boot loader then throw an exception if its
|
||||
@ -4715,12 +4940,13 @@ void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const {
|
||||
const bool is_super = (flags & JVM_ACC_SUPER) != 0;
|
||||
const bool is_enum = (flags & JVM_ACC_ENUM) != 0;
|
||||
const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0;
|
||||
const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION;
|
||||
const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION;
|
||||
const bool major_gte_14 = _major_version >= JAVA_14_VERSION;
|
||||
|
||||
if ((is_abstract && is_final) ||
|
||||
(is_interface && !is_abstract) ||
|
||||
(is_interface && major_gte_15 && (is_super || is_enum)) ||
|
||||
(!is_interface && major_gte_15 && is_annotation)) {
|
||||
(is_interface && major_gte_1_5 && (is_super || is_enum)) ||
|
||||
(!is_interface && major_gte_1_5 && is_annotation)) {
|
||||
ResourceMark rm(THREAD);
|
||||
Exceptions::fthrow(
|
||||
THREAD_AND_LOCATION,
|
||||
@ -4816,14 +5042,14 @@ void ClassFileParser::verify_legal_field_modifiers(jint flags,
|
||||
const bool is_volatile = (flags & JVM_ACC_VOLATILE) != 0;
|
||||
const bool is_transient = (flags & JVM_ACC_TRANSIENT) != 0;
|
||||
const bool is_enum = (flags & JVM_ACC_ENUM) != 0;
|
||||
const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION;
|
||||
const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION;
|
||||
|
||||
bool is_illegal = false;
|
||||
|
||||
if (is_interface) {
|
||||
if (!is_public || !is_static || !is_final || is_private ||
|
||||
is_protected || is_volatile || is_transient ||
|
||||
(major_gte_15 && is_enum)) {
|
||||
(major_gte_1_5 && is_enum)) {
|
||||
is_illegal = true;
|
||||
}
|
||||
} else { // not interface
|
||||
@ -4859,7 +5085,7 @@ void ClassFileParser::verify_legal_method_modifiers(jint flags,
|
||||
const bool is_strict = (flags & JVM_ACC_STRICT) != 0;
|
||||
const bool is_synchronized = (flags & JVM_ACC_SYNCHRONIZED) != 0;
|
||||
const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0;
|
||||
const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION;
|
||||
const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION;
|
||||
const bool major_gte_8 = _major_version >= JAVA_8_VERSION;
|
||||
const bool is_initializer = (name == vmSymbols::object_initializer_name());
|
||||
|
||||
@ -4882,7 +5108,7 @@ void ClassFileParser::verify_legal_method_modifiers(jint flags,
|
||||
(is_abstract && (is_private || is_static || is_strict))) {
|
||||
is_illegal = true;
|
||||
}
|
||||
} else if (major_gte_15) {
|
||||
} else if (major_gte_1_5) {
|
||||
// Class file version in the interval [JAVA_1_5_VERSION, JAVA_8_VERSION)
|
||||
if (!is_public || is_private || is_protected || is_static || is_final ||
|
||||
is_synchronized || is_native || !is_abstract || is_strict) {
|
||||
@ -4900,13 +5126,13 @@ void ClassFileParser::verify_legal_method_modifiers(jint flags,
|
||||
} else {
|
||||
if (is_initializer) {
|
||||
if (is_static || is_final || is_synchronized || is_native ||
|
||||
is_abstract || (major_gte_15 && is_bridge)) {
|
||||
is_abstract || (major_gte_1_5 && is_bridge)) {
|
||||
is_illegal = true;
|
||||
}
|
||||
} else { // not initializer
|
||||
if (is_abstract) {
|
||||
if ((is_final || is_native || is_private || is_static ||
|
||||
(major_gte_15 && (is_synchronized || is_strict)))) {
|
||||
(major_gte_1_5 && (is_synchronized || is_strict)))) {
|
||||
is_illegal = true;
|
||||
}
|
||||
}
|
||||
@ -5495,6 +5721,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
|
||||
assert(NULL == _nest_members, "invariant");
|
||||
assert(NULL == _local_interfaces, "invariant");
|
||||
assert(NULL == _combined_annotations, "invariant");
|
||||
assert(NULL == _record_components, "invariant");
|
||||
|
||||
if (_has_final_method) {
|
||||
ik->set_has_final_method();
|
||||
@ -5776,6 +6003,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
|
||||
_inner_classes(NULL),
|
||||
_nest_members(NULL),
|
||||
_nest_host(0),
|
||||
_record_components(NULL),
|
||||
_local_interfaces(NULL),
|
||||
_transitive_interfaces(NULL),
|
||||
_combined_annotations(NULL),
|
||||
@ -5886,6 +6114,7 @@ void ClassFileParser::clear_class_metadata() {
|
||||
_combined_annotations = NULL;
|
||||
_class_annotations = _class_type_annotations = NULL;
|
||||
_fields_annotations = _fields_type_annotations = NULL;
|
||||
_record_components = NULL;
|
||||
}
|
||||
|
||||
// Destructor to clean up
|
||||
@ -5913,6 +6142,10 @@ ClassFileParser::~ClassFileParser() {
|
||||
MetadataFactory::free_array<u2>(_loader_data, _nest_members);
|
||||
}
|
||||
|
||||
if (_record_components != NULL) {
|
||||
InstanceKlass::deallocate_record_components(_loader_data, _record_components);
|
||||
}
|
||||
|
||||
// Free interfaces
|
||||
InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
|
||||
_local_interfaces, _transitive_interfaces);
|
||||
|
@ -42,6 +42,7 @@ class FieldInfo;
|
||||
template <typename T>
|
||||
class GrowableArray;
|
||||
class InstanceKlass;
|
||||
class RecordComponent;
|
||||
class Symbol;
|
||||
class TempNewSymbol;
|
||||
|
||||
@ -98,6 +99,7 @@ class ClassFileParser {
|
||||
Array<u2>* _inner_classes;
|
||||
Array<u2>* _nest_members;
|
||||
u2 _nest_host;
|
||||
Array<RecordComponent*>* _record_components;
|
||||
Array<InstanceKlass*>* _local_interfaces;
|
||||
Array<InstanceKlass*>* _transitive_interfaces;
|
||||
Annotations* _combined_annotations;
|
||||
@ -287,6 +289,13 @@ class ClassFileParser {
|
||||
const u1* const nest_members_attribute_start,
|
||||
TRAPS);
|
||||
|
||||
u2 parse_classfile_record_attribute(const ClassFileStream* const cfs,
|
||||
const ConstantPool* cp,
|
||||
const u1* const record_attribute_start,
|
||||
TRAPS);
|
||||
|
||||
bool supports_records();
|
||||
|
||||
void parse_classfile_attributes(const ClassFileStream* const cfs,
|
||||
ConstantPool* cp,
|
||||
ClassAnnotationCollector* parsed_annotations,
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "oops/recordComponent.hpp"
|
||||
#include "oops/typeArrayOop.inline.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "prims/resolvedMethodTable.hpp"
|
||||
@ -3148,6 +3149,64 @@ void java_lang_reflect_Field::set_annotations(oop field, oop value) {
|
||||
field->obj_field_put(annotations_offset, value);
|
||||
}
|
||||
|
||||
oop java_lang_reflect_RecordComponent::create(InstanceKlass* holder, RecordComponent* component, TRAPS) {
|
||||
// Allocate java.lang.reflect.RecordComponent instance
|
||||
HandleMark hm(THREAD);
|
||||
InstanceKlass* ik = SystemDictionary::RecordComponent_klass();
|
||||
assert(ik != NULL, "must be loaded");
|
||||
ik->initialize(CHECK_NULL);
|
||||
|
||||
Handle element = ik->allocate_instance_handle(CHECK_NULL);
|
||||
|
||||
Handle decl_class(THREAD, holder->java_mirror());
|
||||
java_lang_reflect_RecordComponent::set_clazz(element(), decl_class());
|
||||
|
||||
Symbol* name = holder->constants()->symbol_at(component->name_index()); // name_index is a utf8
|
||||
oop component_name = StringTable::intern(name, CHECK_NULL);
|
||||
java_lang_reflect_RecordComponent::set_name(element(), component_name);
|
||||
|
||||
Symbol* type = holder->constants()->symbol_at(component->descriptor_index());
|
||||
Handle component_type_h =
|
||||
SystemDictionary::find_java_mirror_for_type(type, holder, SignatureStream::NCDFError, CHECK_NULL);
|
||||
java_lang_reflect_RecordComponent::set_type(element(), component_type_h());
|
||||
|
||||
Method* accessor_method = NULL;
|
||||
{
|
||||
// Prepend "()" to type to create the full method signature.
|
||||
ResourceMark rm(THREAD);
|
||||
int sig_len = type->utf8_length() + 3; // "()" and null char
|
||||
char* sig = NEW_RESOURCE_ARRAY(char, sig_len);
|
||||
jio_snprintf(sig, sig_len, "%c%c%s", JVM_SIGNATURE_FUNC, JVM_SIGNATURE_ENDFUNC, type->as_C_string());
|
||||
TempNewSymbol full_sig = SymbolTable::new_symbol(sig);
|
||||
accessor_method = holder->find_instance_method(name, full_sig);
|
||||
}
|
||||
|
||||
if (accessor_method != NULL) {
|
||||
methodHandle method(THREAD, accessor_method);
|
||||
oop m = Reflection::new_method(method, false, CHECK_NULL);
|
||||
java_lang_reflect_RecordComponent::set_accessor(element(), m);
|
||||
} else {
|
||||
java_lang_reflect_RecordComponent::set_accessor(element(), NULL);
|
||||
}
|
||||
|
||||
int sig_index = component->generic_signature_index();
|
||||
if (sig_index > 0) {
|
||||
Symbol* sig = holder->constants()->symbol_at(sig_index); // sig_index is a utf8
|
||||
oop component_sig = StringTable::intern(sig, CHECK_NULL);
|
||||
java_lang_reflect_RecordComponent::set_signature(element(), component_sig);
|
||||
} else {
|
||||
java_lang_reflect_RecordComponent::set_signature(element(), NULL);
|
||||
}
|
||||
|
||||
typeArrayOop annotation_oop = Annotations::make_java_array(component->annotations(), CHECK_NULL);
|
||||
java_lang_reflect_RecordComponent::set_annotations(element(), annotation_oop);
|
||||
|
||||
typeArrayOop type_annotation_oop = Annotations::make_java_array(component->type_annotations(), CHECK_NULL);
|
||||
java_lang_reflect_RecordComponent::set_typeAnnotations(element(), type_annotation_oop);
|
||||
|
||||
return element();
|
||||
}
|
||||
|
||||
#define CONSTANTPOOL_FIELDS_DO(macro) \
|
||||
macro(_oop_offset, k, "constantPoolOop", object_signature, false)
|
||||
|
||||
@ -4311,6 +4370,13 @@ int java_lang_Short_ShortCache::_static_cache_offset;
|
||||
int java_lang_Byte_ByteCache::_static_cache_offset;
|
||||
int java_lang_Boolean::_static_TRUE_offset;
|
||||
int java_lang_Boolean::_static_FALSE_offset;
|
||||
int java_lang_reflect_RecordComponent::clazz_offset;
|
||||
int java_lang_reflect_RecordComponent::name_offset;
|
||||
int java_lang_reflect_RecordComponent::type_offset;
|
||||
int java_lang_reflect_RecordComponent::accessor_offset;
|
||||
int java_lang_reflect_RecordComponent::signature_offset;
|
||||
int java_lang_reflect_RecordComponent::annotations_offset;
|
||||
int java_lang_reflect_RecordComponent::typeAnnotations_offset;
|
||||
|
||||
|
||||
|
||||
@ -4662,6 +4728,55 @@ static int member_offset(int hardcoded_offset) {
|
||||
return (hardcoded_offset * heapOopSize) + instanceOopDesc::base_offset_in_bytes();
|
||||
}
|
||||
|
||||
#define RECORDCOMPONENT_FIELDS_DO(macro) \
|
||||
macro(clazz_offset, k, "clazz", class_signature, false); \
|
||||
macro(name_offset, k, "name", string_signature, false); \
|
||||
macro(type_offset, k, "type", class_signature, false); \
|
||||
macro(accessor_offset, k, "accessor", reflect_method_signature, false); \
|
||||
macro(signature_offset, k, "signature", string_signature, false); \
|
||||
macro(annotations_offset, k, "annotations", byte_array_signature, false); \
|
||||
macro(typeAnnotations_offset, k, "typeAnnotations", byte_array_signature, false);
|
||||
|
||||
// Support for java_lang_reflect_RecordComponent
|
||||
void java_lang_reflect_RecordComponent::compute_offsets() {
|
||||
InstanceKlass* k = SystemDictionary::RecordComponent_klass();
|
||||
RECORDCOMPONENT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
|
||||
}
|
||||
|
||||
#if INCLUDE_CDS
|
||||
void java_lang_reflect_RecordComponent::serialize_offsets(SerializeClosure* f) {
|
||||
RECORDCOMPONENT_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
|
||||
}
|
||||
#endif
|
||||
|
||||
void java_lang_reflect_RecordComponent::set_clazz(oop element, oop value) {
|
||||
element->obj_field_put(clazz_offset, value);
|
||||
}
|
||||
|
||||
void java_lang_reflect_RecordComponent::set_name(oop element, oop value) {
|
||||
element->obj_field_put(name_offset, value);
|
||||
}
|
||||
|
||||
void java_lang_reflect_RecordComponent::set_type(oop element, oop value) {
|
||||
element->obj_field_put(type_offset, value);
|
||||
}
|
||||
|
||||
void java_lang_reflect_RecordComponent::set_accessor(oop element, oop value) {
|
||||
element->obj_field_put(accessor_offset, value);
|
||||
}
|
||||
|
||||
void java_lang_reflect_RecordComponent::set_signature(oop element, oop value) {
|
||||
element->obj_field_put(signature_offset, value);
|
||||
}
|
||||
|
||||
void java_lang_reflect_RecordComponent::set_annotations(oop element, oop value) {
|
||||
element->obj_field_put(annotations_offset, value);
|
||||
}
|
||||
|
||||
void java_lang_reflect_RecordComponent::set_typeAnnotations(oop element, oop value) {
|
||||
element->obj_field_put(typeAnnotations_offset, value);
|
||||
}
|
||||
|
||||
// Compute hard-coded offsets
|
||||
// Invoked before SystemDictionary::initialize, so pre-loaded classes
|
||||
// are not available to determine the offset_of_static_fields.
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include "oops/oop.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
|
||||
class RecordComponent;
|
||||
|
||||
// Interface for manipulating the basic Java classes.
|
||||
//
|
||||
// All dependencies on layout of actual Java classes should be kept here.
|
||||
@ -73,6 +75,7 @@
|
||||
f(java_lang_reflect_Method) \
|
||||
f(java_lang_reflect_Constructor) \
|
||||
f(java_lang_reflect_Field) \
|
||||
f(java_lang_reflect_RecordComponent) \
|
||||
f(java_nio_Buffer) \
|
||||
f(reflect_ConstantPool) \
|
||||
f(reflect_UnsafeStaticFieldAccessorImpl) \
|
||||
@ -1483,6 +1486,39 @@ class java_lang_LiveStackFrameInfo: AllStatic {
|
||||
friend class JavaClasses;
|
||||
};
|
||||
|
||||
// Interface to java.lang.reflect.RecordComponent objects
|
||||
|
||||
class java_lang_reflect_RecordComponent: AllStatic {
|
||||
private:
|
||||
static int clazz_offset;
|
||||
static int name_offset;
|
||||
static int type_offset;
|
||||
static int accessor_offset;
|
||||
static int signature_offset;
|
||||
static int annotations_offset;
|
||||
static int typeAnnotations_offset;
|
||||
|
||||
// Setters
|
||||
static void set_clazz(oop element, oop value);
|
||||
static void set_name(oop element, oop value);
|
||||
static void set_type(oop element, oop value);
|
||||
static void set_accessor(oop element, oop value);
|
||||
static void set_signature(oop element, oop value);
|
||||
static void set_annotations(oop element, oop value);
|
||||
static void set_typeAnnotations(oop element, oop value);
|
||||
|
||||
public:
|
||||
// Create an instance of RecordComponent
|
||||
static oop create(InstanceKlass* holder, RecordComponent* component, TRAPS);
|
||||
|
||||
static void compute_offsets();
|
||||
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
|
||||
|
||||
// Debugging
|
||||
friend class JavaClasses;
|
||||
};
|
||||
|
||||
|
||||
// Interface to java.lang.AssertionStatusDirectives objects
|
||||
|
||||
class java_lang_AssertionStatusDirectives: AllStatic {
|
||||
|
@ -119,6 +119,7 @@ class GCTimer;
|
||||
do_klass(AccessController_klass, java_security_AccessController ) \
|
||||
do_klass(SecureClassLoader_klass, java_security_SecureClassLoader ) \
|
||||
do_klass(ClassNotFoundException_klass, java_lang_ClassNotFoundException ) \
|
||||
do_klass(Record_klass, java_lang_Record ) \
|
||||
do_klass(NoClassDefFoundError_klass, java_lang_NoClassDefFoundError ) \
|
||||
do_klass(LinkageError_klass, java_lang_LinkageError ) \
|
||||
do_klass(ClassCastException_klass, java_lang_ClassCastException ) \
|
||||
@ -217,6 +218,9 @@ class GCTimer;
|
||||
/* force inline of iterators */ \
|
||||
do_klass(Iterator_klass, java_util_Iterator ) \
|
||||
\
|
||||
/* support for records */ \
|
||||
do_klass(RecordComponent_klass, java_lang_reflect_RecordComponent ) \
|
||||
\
|
||||
/*end*/
|
||||
|
||||
class SystemDictionary : AllStatic {
|
||||
|
@ -94,6 +94,7 @@
|
||||
template(java_lang_reflect_Field, "java/lang/reflect/Field") \
|
||||
template(java_lang_reflect_Parameter, "java/lang/reflect/Parameter") \
|
||||
template(java_lang_reflect_Array, "java/lang/reflect/Array") \
|
||||
template(java_lang_reflect_RecordComponent, "java/lang/reflect/RecordComponent") \
|
||||
template(java_lang_StringBuffer, "java/lang/StringBuffer") \
|
||||
template(java_lang_StringBuilder, "java/lang/StringBuilder") \
|
||||
template(java_lang_CharSequence, "java/lang/CharSequence") \
|
||||
@ -127,6 +128,7 @@
|
||||
template(jdk_internal_vm_PostVMInitHook, "jdk/internal/vm/PostVMInitHook") \
|
||||
template(sun_net_www_ParseUtil, "sun/net/www/ParseUtil") \
|
||||
template(java_util_Iterator, "java/util/Iterator") \
|
||||
template(java_lang_Record, "java/lang/Record") \
|
||||
\
|
||||
template(jdk_internal_loader_ClassLoaders_AppClassLoader, "jdk/internal/loader/ClassLoaders$AppClassLoader") \
|
||||
template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \
|
||||
@ -161,6 +163,7 @@
|
||||
template(tag_deprecated, "Deprecated") \
|
||||
template(tag_source_debug_extension, "SourceDebugExtension") \
|
||||
template(tag_signature, "Signature") \
|
||||
template(tag_record, "Record") \
|
||||
template(tag_runtime_visible_annotations, "RuntimeVisibleAnnotations") \
|
||||
template(tag_runtime_invisible_annotations, "RuntimeInvisibleAnnotations") \
|
||||
template(tag_runtime_visible_parameter_annotations, "RuntimeVisibleParameterAnnotations") \
|
||||
@ -562,6 +565,7 @@
|
||||
template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \
|
||||
template(int_String_signature, "(I)Ljava/lang/String;") \
|
||||
template(boolean_boolean_int_signature, "(ZZ)I") \
|
||||
template(reflect_method_signature, "Ljava/lang/reflect/Method;") \
|
||||
/* signature symbols needed by intrinsics */ \
|
||||
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \
|
||||
\
|
||||
|
@ -518,6 +518,7 @@ JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, jboolean publicOnly);
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly);
|
||||
|
||||
|
||||
/* Differs from JVM_GetClassModifiers in treatment of inner classes.
|
||||
This returns the access flags for the class as specified in the
|
||||
class file rather than searching the InnerClasses attribute (if
|
||||
@ -538,6 +539,14 @@ JVM_GetNestHost(JNIEnv *env, jclass current);
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
JVM_GetNestMembers(JNIEnv *env, jclass current);
|
||||
|
||||
/* Records - since JDK 14 */
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
JVM_IsRecord(JNIEnv *env, jclass cls);
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL
|
||||
JVM_GetRecordComponents(JNIEnv *env, jclass ofClass);
|
||||
|
||||
/* The following two reflection routines are still needed due to startup time issues */
|
||||
/*
|
||||
* java.lang.reflect.Method
|
||||
|
@ -137,6 +137,7 @@
|
||||
LOG_TAG(parser) \
|
||||
LOG_TAG(ptrqueue) \
|
||||
LOG_TAG(purge) \
|
||||
LOG_TAG(record) \
|
||||
LOG_TAG(resolve) \
|
||||
LOG_TAG(safepoint) \
|
||||
LOG_TAG(sampling) \
|
||||
|
@ -300,7 +300,8 @@ class MetaspaceObj {
|
||||
f(ConstantPool) \
|
||||
f(ConstantPoolCache) \
|
||||
f(Annotations) \
|
||||
f(MethodCounters)
|
||||
f(MethodCounters) \
|
||||
f(RecordComponent)
|
||||
|
||||
#define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type,
|
||||
#define METASPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name;
|
||||
|
@ -88,6 +88,8 @@
|
||||
"Number of bytes used by the InstanceKlass::inner_classes() array") \
|
||||
f(nest_members_bytes, IK_nest_members, \
|
||||
"Number of bytes used by the InstanceKlass::nest_members() array") \
|
||||
f(record_components_bytes, IK_record_components, \
|
||||
"Number of bytes used by the InstanceKlass::record_components() array") \
|
||||
f(signers_bytes, IK_signers, \
|
||||
"Number of bytes used by the InstanceKlass::singers() array") \
|
||||
f(class_annotations_bytes, class_annotations, \
|
||||
|
@ -823,6 +823,7 @@ intptr_t* MetaspaceShared::fix_cpp_vtable_for_dynamic_archive(MetaspaceObj::Type
|
||||
case MetaspaceObj::ConstantPoolCacheType:
|
||||
case MetaspaceObj::AnnotationsType:
|
||||
case MetaspaceObj::MethodCountersType:
|
||||
case MetaspaceObj::RecordComponentType:
|
||||
// These have no vtables.
|
||||
break;
|
||||
case MetaspaceObj::ClassType:
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include "oops/klass.inline.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/recordComponent.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "prims/jvmtiExport.hpp"
|
||||
#include "prims/jvmtiRedefineClasses.hpp"
|
||||
@ -436,6 +437,7 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass
|
||||
_nest_members(NULL),
|
||||
_nest_host_index(0),
|
||||
_nest_host(NULL),
|
||||
_record_components(NULL),
|
||||
_static_field_size(parser.static_field_size()),
|
||||
_nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
|
||||
_itable_len(parser.itable_size()),
|
||||
@ -504,6 +506,17 @@ void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data,
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data,
|
||||
Array<RecordComponent*>* record_components) {
|
||||
if (record_components != NULL && !record_components->is_shared()) {
|
||||
for (int i = 0; i < record_components->length(); i++) {
|
||||
RecordComponent* record_component = record_components->at(i);
|
||||
MetadataFactory::free_metadata(loader_data, record_component);
|
||||
}
|
||||
MetadataFactory::free_array<RecordComponent*>(loader_data, record_components);
|
||||
}
|
||||
}
|
||||
|
||||
// This function deallocates the metadata and C heap pointers that the
|
||||
// InstanceKlass points to.
|
||||
void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
|
||||
@ -532,6 +545,9 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
|
||||
deallocate_methods(loader_data, methods());
|
||||
set_methods(NULL);
|
||||
|
||||
deallocate_record_components(loader_data, record_components());
|
||||
set_record_components(NULL);
|
||||
|
||||
if (method_ordering() != NULL &&
|
||||
method_ordering() != Universe::the_empty_int_array() &&
|
||||
!method_ordering()->is_shared()) {
|
||||
@ -2339,6 +2355,7 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
}
|
||||
|
||||
it->push(&_nest_members);
|
||||
it->push(&_record_components);
|
||||
}
|
||||
|
||||
void InstanceKlass::remove_unshareable_info() {
|
||||
@ -3270,6 +3287,9 @@ void InstanceKlass::print_on(outputStream* st) const {
|
||||
}
|
||||
st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr();
|
||||
st->print(BULLET"nest members: "); nest_members()->print_value_on(st); st->cr();
|
||||
if (record_components() != NULL) {
|
||||
st->print(BULLET"record components: "); record_components()->print_value_on(st); st->cr();
|
||||
}
|
||||
if (java_mirror() != NULL) {
|
||||
st->print(BULLET"java mirror: ");
|
||||
java_mirror()->print_value_on(st);
|
||||
@ -3532,6 +3552,7 @@ void InstanceKlass::collect_statistics(KlassSizeStats *sz) const {
|
||||
n += (sz->_fields_bytes = sz->count_array(fields()));
|
||||
n += (sz->_inner_classes_bytes = sz->count_array(inner_classes()));
|
||||
n += (sz->_nest_members_bytes = sz->count_array(nest_members()));
|
||||
n += (sz->_record_components_bytes = sz->count_array(record_components()));
|
||||
sz->_ro_bytes += n;
|
||||
|
||||
const ConstantPool* cp = constants();
|
||||
@ -3554,6 +3575,17 @@ void InstanceKlass::collect_statistics(KlassSizeStats *sz) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Array<RecordComponent*>* components = record_components();
|
||||
if (components != NULL) {
|
||||
for (int i = 0; i < components->length(); i++) {
|
||||
RecordComponent* component = components->at(i);
|
||||
if (component != NULL) {
|
||||
component->collect_statistics(sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif // INCLUDE_SERVICES
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "jfr/support/jfrKlassExtension.hpp"
|
||||
#endif
|
||||
|
||||
class RecordComponent;
|
||||
|
||||
// An InstanceKlass is the VM level representation of a Java class.
|
||||
// It contains all information needed for at class at execution runtime.
|
||||
@ -182,6 +183,9 @@ class InstanceKlass: public Klass {
|
||||
// By always being set it makes nest-member access checks simpler.
|
||||
InstanceKlass* _nest_host;
|
||||
|
||||
// The contents of the Record attribute.
|
||||
Array<RecordComponent*>* _record_components;
|
||||
|
||||
// the source debug extension for this klass, NULL if not specified.
|
||||
// Specified as UTF-8 string without terminating zero byte in the classfile,
|
||||
// it is stored in the instanceklass as a NULL-terminated UTF-8 string
|
||||
@ -448,9 +452,17 @@ class InstanceKlass: public Klass {
|
||||
jushort nest_host_index() const { return _nest_host_index; }
|
||||
void set_nest_host_index(u2 i) { _nest_host_index = i; }
|
||||
|
||||
// record components
|
||||
Array<RecordComponent*>* record_components() const { return _record_components; }
|
||||
void set_record_components(Array<RecordComponent*>* record_components) {
|
||||
_record_components = record_components;
|
||||
}
|
||||
bool is_record() const { return _record_components != NULL; }
|
||||
|
||||
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;
|
||||
|
||||
public:
|
||||
// Returns nest-host class, resolving and validating it if needed
|
||||
// Returns NULL if an exception occurs during loading, or validation fails
|
||||
@ -1152,6 +1164,8 @@ public:
|
||||
const Klass* super_klass,
|
||||
Array<InstanceKlass*>* local_interfaces,
|
||||
Array<InstanceKlass*>* transitive_interfaces);
|
||||
void static deallocate_record_components(ClassLoaderData* loader_data,
|
||||
Array<RecordComponent*>* record_component);
|
||||
|
||||
// The constant pool is on stack if any of the methods are executing or
|
||||
// referenced by handles.
|
||||
|
97
src/hotspot/share/oops/recordComponent.cpp
Normal file
97
src/hotspot/share/oops/recordComponent.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/heapInspection.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/metaspace.hpp"
|
||||
#include "memory/metaspaceClosure.hpp"
|
||||
#include "oops/annotations.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/recordComponent.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
RecordComponent* RecordComponent::allocate(ClassLoaderData* loader_data,
|
||||
u2 name_index, u2 descriptor_index,
|
||||
u2 attributes_count,
|
||||
u2 generic_signature_index,
|
||||
AnnotationArray* annotations,
|
||||
AnnotationArray* type_annotations, TRAPS) {
|
||||
return new (loader_data, size(), MetaspaceObj::RecordComponentType, THREAD)
|
||||
RecordComponent(name_index, descriptor_index, attributes_count,
|
||||
generic_signature_index, annotations, type_annotations);
|
||||
}
|
||||
|
||||
void RecordComponent::deallocate_contents(ClassLoaderData* loader_data) {
|
||||
if (annotations() != NULL) {
|
||||
MetadataFactory::free_array<u1>(loader_data, annotations());
|
||||
}
|
||||
if (type_annotations() != NULL) {
|
||||
MetadataFactory::free_array<u1>(loader_data, type_annotations());
|
||||
}
|
||||
}
|
||||
|
||||
void RecordComponent::metaspace_pointers_do(MetaspaceClosure* it) {
|
||||
log_trace(cds)("Iter(RecordComponent): %p", this);
|
||||
it->push(&_annotations);
|
||||
it->push(&_type_annotations);
|
||||
}
|
||||
|
||||
void RecordComponent::print_value_on(outputStream* st) const {
|
||||
st->print("RecordComponent(" INTPTR_FORMAT ")", p2i(this));
|
||||
}
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
void RecordComponent::collect_statistics(KlassSizeStats *sz) const {
|
||||
if (_annotations != NULL) {
|
||||
sz->_annotations_bytes += sz->count(_annotations);
|
||||
sz->_ro_bytes += sz->count(_annotations);
|
||||
}
|
||||
if (_type_annotations != NULL) {
|
||||
sz->_annotations_bytes += sz->count(_type_annotations);
|
||||
sz->_ro_bytes += sz->count(_type_annotations);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef PRODUCT
|
||||
void RecordComponent::print_on(outputStream* st) const {
|
||||
st->print("name_index: %d", _name_index);
|
||||
st->print(" - descriptor_index: %d", _descriptor_index);
|
||||
st->print(" - attributes_count: %d", _attributes_count);
|
||||
if (_generic_signature_index != 0) {
|
||||
st->print(" - generic_signature_index: %d", _generic_signature_index);
|
||||
}
|
||||
st->cr();
|
||||
if (_annotations != NULL) {
|
||||
st->print_cr("record component annotations");
|
||||
_annotations->print_value_on(st);
|
||||
}
|
||||
if (_type_annotations != NULL) {
|
||||
st->print_cr("record component type annotations");
|
||||
_type_annotations->print_value_on(st);
|
||||
}
|
||||
}
|
||||
#endif // PRODUCT
|
107
src/hotspot/share/oops/recordComponent.hpp
Normal file
107
src/hotspot/share/oops/recordComponent.hpp
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_OOPS_RECORDCOMPONENT_HPP
|
||||
#define SHARE_OOPS_RECORDCOMPONENT_HPP
|
||||
|
||||
#include "oops/annotations.hpp"
|
||||
#include "oops/metadata.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
class KlassSizeStats;
|
||||
|
||||
// This class stores information extracted from the Record class attribute.
|
||||
class RecordComponent: public MetaspaceObj {
|
||||
private:
|
||||
AnnotationArray* _annotations;
|
||||
AnnotationArray* _type_annotations;
|
||||
u2 _name_index;
|
||||
u2 _descriptor_index;
|
||||
u2 _attributes_count;
|
||||
|
||||
// generic_signature_index gets set if the Record component has a Signature
|
||||
// attribute. A zero value indicates that there was no Signature attribute.
|
||||
u2 _generic_signature_index;
|
||||
|
||||
public:
|
||||
RecordComponent(u2 name_index, u2 descriptor_index, u2 attributes_count,
|
||||
u2 generic_signature_index, AnnotationArray* annotations,
|
||||
AnnotationArray* type_annotations):
|
||||
_annotations(annotations), _type_annotations(type_annotations),
|
||||
_name_index(name_index), _descriptor_index(descriptor_index),
|
||||
_attributes_count(attributes_count),
|
||||
_generic_signature_index(generic_signature_index) { }
|
||||
|
||||
// Allocate instance of this class
|
||||
static RecordComponent* allocate(ClassLoaderData* loader_data,
|
||||
u2 name_index, u2 descriptor_index,
|
||||
u2 attributes_count,
|
||||
u2 generic_signature_index,
|
||||
AnnotationArray* annotations,
|
||||
AnnotationArray* type_annotations, TRAPS);
|
||||
|
||||
void deallocate_contents(ClassLoaderData* loader_data);
|
||||
|
||||
u2 name_index() const { return _name_index; }
|
||||
void set_name_index(u2 name_index) { _name_index = name_index; }
|
||||
|
||||
u2 descriptor_index() const { return _descriptor_index; }
|
||||
void set_descriptor_index(u2 descriptor_index) {
|
||||
_descriptor_index = descriptor_index;
|
||||
}
|
||||
|
||||
u2 attributes_count() const { return _attributes_count; }
|
||||
|
||||
u2 generic_signature_index() const { return _generic_signature_index; }
|
||||
void set_generic_signature_index(u2 generic_signature_index) {
|
||||
_generic_signature_index = generic_signature_index;
|
||||
}
|
||||
|
||||
AnnotationArray* annotations() const { return _annotations; }
|
||||
AnnotationArray* type_annotations() const { return _type_annotations; }
|
||||
|
||||
// Size of RecordComponent, not including size of any annotations.
|
||||
static int size() { return sizeof(RecordComponent) / wordSize; }
|
||||
|
||||
void metaspace_pointers_do(MetaspaceClosure* it);
|
||||
MetaspaceObj::Type type() const { return RecordComponentType; }
|
||||
|
||||
// Record_components should be stored in the read-only region of CDS archive.
|
||||
static bool is_read_only_by_default() { return true; }
|
||||
DEBUG_ONLY(bool on_stack() { return false; }) // for template
|
||||
|
||||
#if INCLUDE_SERVICES
|
||||
void collect_statistics(KlassSizeStats *sz) const;
|
||||
#endif
|
||||
|
||||
bool is_klass() const { return false; }
|
||||
|
||||
#ifndef PRODUCT
|
||||
void print_on(outputStream* st) const;
|
||||
#endif
|
||||
void print_value_on(outputStream* st) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // SHARE_OOPS_RECORDCOMPONENT_HPP
|
@ -51,6 +51,7 @@
|
||||
#include "oops/fieldStreams.inline.hpp"
|
||||
#include "oops/instanceKlass.hpp"
|
||||
#include "oops/method.hpp"
|
||||
#include "oops/recordComponent.hpp"
|
||||
#include "oops/objArrayKlass.hpp"
|
||||
#include "oops/objArrayOop.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
@ -1693,6 +1694,54 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
|
||||
}
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(jboolean, JVM_IsRecord(JNIEnv *env, jclass cls))
|
||||
{
|
||||
JVMWrapper("JVM_IsRecord");
|
||||
Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls));
|
||||
if (k != NULL && k->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||
return ik->is_record();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass))
|
||||
{
|
||||
JVMWrapper("JVM_GetRecordComponents");
|
||||
Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass));
|
||||
assert(c->is_instance_klass(), "must be");
|
||||
InstanceKlass* ik = InstanceKlass::cast(c);
|
||||
|
||||
if (ik->is_record()) {
|
||||
Array<RecordComponent*>* components = ik->record_components();
|
||||
assert(components != NULL, "components should not be NULL");
|
||||
{
|
||||
JvmtiVMObjectAllocEventCollector oam;
|
||||
constantPoolHandle cp(THREAD, ik->constants());
|
||||
int length = components->length();
|
||||
assert(length >= 0, "unexpected record_components length");
|
||||
objArrayOop record_components =
|
||||
oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), length, CHECK_NULL);
|
||||
objArrayHandle components_h (THREAD, record_components);
|
||||
|
||||
for (int x = 0; x < length; x++) {
|
||||
RecordComponent* component = components->at(x);
|
||||
assert(component != NULL, "unexpected NULL record component");
|
||||
oop component_oop = java_lang_reflect_RecordComponent::create(ik, component, CHECK_NULL);
|
||||
components_h->obj_at_put(x, component_oop);
|
||||
}
|
||||
return (jobjectArray)JNIHandles::make_local(components_h());
|
||||
}
|
||||
}
|
||||
|
||||
// Return empty array if ofClass is not a record.
|
||||
objArrayOop result = oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), 0, CHECK_NULL);
|
||||
return (jobjectArray)JNIHandles::make_local(env, result);
|
||||
}
|
||||
JVM_END
|
||||
|
||||
static bool select_method(const methodHandle& method, bool want_constructor) {
|
||||
if (want_constructor) {
|
||||
return (method->is_initializer() && !method->is_static());
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -27,6 +27,7 @@
|
||||
#include "interpreter/bytecodeStream.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/fieldStreams.inline.hpp"
|
||||
#include "oops/recordComponent.hpp"
|
||||
#include "prims/jvmtiClassFileReconstituter.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#include "runtime/signature.hpp"
|
||||
@ -423,6 +424,57 @@ void JvmtiClassFileReconstituter::write_nest_members_attribute() {
|
||||
}
|
||||
}
|
||||
|
||||
// Record {
|
||||
// u2 attribute_name_index;
|
||||
// u4 attribute_length;
|
||||
// u2 components_count;
|
||||
// component_info components[components_count];
|
||||
// }
|
||||
// component_info {
|
||||
// u2 name_index;
|
||||
// u2 descriptor_index
|
||||
// u2 attributes_count;
|
||||
// attribute_info_attributes[attributes_count];
|
||||
// }
|
||||
void JvmtiClassFileReconstituter::write_record_attribute() {
|
||||
Array<RecordComponent*>* components = ik()->record_components();
|
||||
int number_of_components = components->length();
|
||||
|
||||
// Each component has a u2 for name, descr, attribute count
|
||||
int length = sizeof(u2) + (sizeof(u2) * 3 * number_of_components);
|
||||
for (int x = 0; x < number_of_components; x++) {
|
||||
RecordComponent* component = components->at(x);
|
||||
if (component->generic_signature_index() != 0) {
|
||||
length += 8; // Signature attribute size
|
||||
assert(component->attributes_count() > 0, "Bad component attributes count");
|
||||
}
|
||||
if (component->annotations() != NULL) {
|
||||
length += 6 + component->annotations()->length();
|
||||
}
|
||||
if (component->type_annotations() != NULL) {
|
||||
length += 6 + component->type_annotations()->length();
|
||||
}
|
||||
}
|
||||
|
||||
write_attribute_name_index("Record");
|
||||
write_u4(length);
|
||||
write_u2(number_of_components);
|
||||
for (int i = 0; i < number_of_components; i++) {
|
||||
RecordComponent* component = components->at(i);
|
||||
write_u2(component->name_index());
|
||||
write_u2(component->descriptor_index());
|
||||
write_u2(component->attributes_count());
|
||||
if (component->generic_signature_index() != 0) {
|
||||
write_signature_attribute(component->generic_signature_index());
|
||||
}
|
||||
if (component->annotations() != NULL) {
|
||||
write_annotations_attribute("RuntimeVisibleAnnotations", component->annotations());
|
||||
}
|
||||
if (component->type_annotations() != NULL) {
|
||||
write_annotations_attribute("RuntimeVisibleTypeAnnotations", component->type_annotations());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write InnerClasses attribute
|
||||
// JVMSpec| InnerClasses_attribute {
|
||||
@ -699,6 +751,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
|
||||
if (ik()->nest_members() != Universe::the_empty_short_array()) {
|
||||
++attr_count;
|
||||
}
|
||||
if (ik()->record_components() != NULL) {
|
||||
++attr_count;
|
||||
}
|
||||
|
||||
write_u2(attr_count);
|
||||
|
||||
@ -729,6 +784,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
|
||||
if (ik()->nest_members() != Universe::the_empty_short_array()) {
|
||||
write_nest_members_attribute();
|
||||
}
|
||||
if (ik()->record_components() != NULL) {
|
||||
write_record_attribute();
|
||||
}
|
||||
}
|
||||
|
||||
// Write the method information portion of ClassFile structure
|
||||
|
@ -118,6 +118,7 @@ class JvmtiClassFileReconstituter : public JvmtiConstantPoolReconstituter {
|
||||
void write_bootstrapmethod_attribute();
|
||||
void write_nest_host_attribute();
|
||||
void write_nest_members_attribute();
|
||||
void write_record_attribute();
|
||||
|
||||
address writeable_address(size_t size);
|
||||
void write_u1(u1 x);
|
||||
|
@ -40,10 +40,12 @@
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
#include "oops/annotations.hpp"
|
||||
#include "oops/constantPool.hpp"
|
||||
#include "oops/fieldStreams.inline.hpp"
|
||||
#include "oops/klassVtable.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "oops/recordComponent.hpp"
|
||||
#include "prims/jvmtiImpl.hpp"
|
||||
#include "prims/jvmtiRedefineClasses.hpp"
|
||||
#include "prims/jvmtiThreadState.inline.hpp"
|
||||
@ -785,6 +787,69 @@ static jvmtiError check_nest_attributes(InstanceKlass* the_class,
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
|
||||
// Return an error status if the class Record attribute was changed.
|
||||
static jvmtiError check_record_attribute(InstanceKlass* the_class, InstanceKlass* scratch_class) {
|
||||
// Get lists of record components.
|
||||
Array<RecordComponent*>* the_record = the_class->record_components();
|
||||
Array<RecordComponent*>* scr_record = scratch_class->record_components();
|
||||
bool the_record_exists = the_record != NULL;
|
||||
bool scr_record_exists = scr_record != NULL;
|
||||
|
||||
if (the_record_exists && scr_record_exists) {
|
||||
int the_num_components = the_record->length();
|
||||
int scr_num_components = scr_record->length();
|
||||
if (the_num_components != scr_num_components) {
|
||||
log_trace(redefine, class, record)
|
||||
("redefined class %s attribute change error: Record num_components=%d changed to num_components=%d",
|
||||
the_class->external_name(), the_num_components, scr_num_components);
|
||||
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
|
||||
}
|
||||
|
||||
// Compare each field in each record component.
|
||||
ConstantPool* the_cp = the_class->constants();
|
||||
ConstantPool* scr_cp = scratch_class->constants();
|
||||
for (int x = 0; x < the_num_components; x++) {
|
||||
RecordComponent* the_component = the_record->at(x);
|
||||
RecordComponent* scr_component = scr_record->at(x);
|
||||
const Symbol* const the_name = the_cp->symbol_at(the_component->name_index());
|
||||
const Symbol* const scr_name = scr_cp->symbol_at(scr_component->name_index());
|
||||
const Symbol* const the_descr = the_cp->symbol_at(the_component->descriptor_index());
|
||||
const Symbol* const scr_descr = scr_cp->symbol_at(scr_component->descriptor_index());
|
||||
if (the_name != scr_name || the_descr != scr_descr) {
|
||||
log_trace(redefine, class, record)
|
||||
("redefined class %s attribute change error: Record name_index, descriptor_index, and/or attributes_count changed",
|
||||
the_class->external_name());
|
||||
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
|
||||
}
|
||||
|
||||
int the_gen_sig = the_component->generic_signature_index();
|
||||
int scr_gen_sig = scr_component->generic_signature_index();
|
||||
const Symbol* const the_gen_sig_sym = (the_gen_sig == 0 ? NULL :
|
||||
the_cp->symbol_at(the_component->generic_signature_index()));
|
||||
const Symbol* const scr_gen_sig_sym = (scr_gen_sig == 0 ? NULL :
|
||||
scr_cp->symbol_at(scr_component->generic_signature_index()));
|
||||
if (the_gen_sig_sym != scr_gen_sig_sym) {
|
||||
log_trace(redefine, class, record)
|
||||
("redefined class %s attribute change error: Record generic_signature attribute changed",
|
||||
the_class->external_name());
|
||||
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
|
||||
}
|
||||
|
||||
// It's okay if a record component's annotations were changed.
|
||||
}
|
||||
|
||||
} else if (the_record_exists ^ scr_record_exists) {
|
||||
const char* action_str = (the_record_exists) ? "removed" : "added";
|
||||
log_trace(redefine, class, record)
|
||||
("redefined class %s attribute change error: Record 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 &&
|
||||
@ -838,6 +903,12 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
|
||||
return err;
|
||||
}
|
||||
|
||||
// Check whether the Record attribute has been changed.
|
||||
err = check_record_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();
|
||||
@ -1711,6 +1782,12 @@ bool VM_RedefineClasses::rewrite_cp_refs(InstanceKlass* scratch_class,
|
||||
return false;
|
||||
}
|
||||
|
||||
// rewrite constant pool references in the Record attribute:
|
||||
if (!rewrite_cp_refs_in_record_attribute(scratch_class, THREAD)) {
|
||||
// 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
|
||||
@ -1809,6 +1886,46 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_nest_attributes(
|
||||
return true;
|
||||
}
|
||||
|
||||
// Rewrite constant pool references in the Record attribute.
|
||||
bool VM_RedefineClasses::rewrite_cp_refs_in_record_attribute(
|
||||
InstanceKlass* scratch_class, TRAPS) {
|
||||
Array<RecordComponent*>* components = scratch_class->record_components();
|
||||
if (components != NULL) {
|
||||
for (int i = 0; i < components->length(); i++) {
|
||||
RecordComponent* component = components->at(i);
|
||||
u2 cp_index = component->name_index();
|
||||
component->set_name_index(find_new_index(cp_index));
|
||||
cp_index = component->descriptor_index();
|
||||
component->set_descriptor_index(find_new_index(cp_index));
|
||||
cp_index = component->generic_signature_index();
|
||||
if (cp_index != 0) {
|
||||
component->set_generic_signature_index(find_new_index(cp_index));
|
||||
}
|
||||
|
||||
AnnotationArray* annotations = component->annotations();
|
||||
if (annotations != NULL && annotations->length() != 0) {
|
||||
int byte_i = 0; // byte index into annotations
|
||||
if (!rewrite_cp_refs_in_annotations_typeArray(annotations, byte_i, THREAD)) {
|
||||
log_debug(redefine, class, annotation)("bad record_component_annotations at %d", i);
|
||||
// propagate failure back to caller
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
AnnotationArray* type_annotations = component->type_annotations();
|
||||
if (type_annotations != NULL && type_annotations->length() != 0) {
|
||||
int byte_i = 0; // byte index into annotations
|
||||
if (!rewrite_cp_refs_in_annotations_typeArray(type_annotations, byte_i, THREAD)) {
|
||||
log_debug(redefine, class, annotation)("bad record_component_type_annotations at %d", i);
|
||||
// propagate failure back to caller
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Rewrite constant pool references in the methods.
|
||||
bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
|
||||
InstanceKlass* scratch_class, TRAPS) {
|
||||
|
@ -472,6 +472,7 @@ class VM_RedefineClasses: public VM_Operation {
|
||||
bool rewrite_cp_refs_in_fields_annotations(
|
||||
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);
|
||||
void rewrite_cp_refs_in_method(methodHandle method,
|
||||
methodHandle * new_method_p, TRAPS);
|
||||
bool rewrite_cp_refs_in_methods(InstanceKlass* scratch_class, TRAPS);
|
||||
|
@ -26,7 +26,9 @@
|
||||
package java.io;
|
||||
|
||||
import java.io.ObjectStreamClass.WeakClassKey;
|
||||
import java.io.ObjectStreamClass.RecordSupport;
|
||||
import java.lang.System.Logger;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Modifier;
|
||||
@ -218,6 +220,39 @@ import sun.reflect.misc.ReflectUtil;
|
||||
* Similarly, any serialPersistentFields or serialVersionUID field declarations
|
||||
* are also ignored--all enum types have a fixed serialVersionUID of 0L.
|
||||
*
|
||||
* @implSpec
|
||||
* <a id="record-serialization"></a>
|
||||
* Records are serialized differently than ordinary serializable or externalizable
|
||||
* objects. The serialized form of a record object is a sequence of values derived
|
||||
* from the record components. The stream format of a record object is the same as
|
||||
* that of an ordinary object in the stream. During deserialization, if the local
|
||||
* class equivalent of the specified stream class descriptor is a record class,
|
||||
* then first the stream fields are read and reconstructed to serve as the record's
|
||||
* component values; and second, a record object is created by invoking the
|
||||
* record's <i>canonical</i> constructor with the component values as arguments (or the
|
||||
* default value for component's type if a component value is absent from the
|
||||
* stream).
|
||||
* Like other serializable or externalizable objects, record objects can function
|
||||
* as the target of back references appearing subsequently in the serialization
|
||||
* stream. However, a cycle in the graph where the record object is referred to,
|
||||
* either directly or transitively, by one of its components, is not preserved.
|
||||
* The record components are deserialized prior to the invocation of the record
|
||||
* constructor, hence this limitation (see
|
||||
* <a href="{@docRoot}/../specs/serialization/serial-arch.html#cyclic-references">
|
||||
* [Section 1.14, "Circular References"</a> for additional information).
|
||||
* The process by which record objects are serialized or externalized cannot be
|
||||
* customized; any class-specific writeObject, readObject, readObjectNoData,
|
||||
* writeExternal, and readExternal methods defined by record classes are
|
||||
* ignored during serialization and deserialization. However, a substitute object
|
||||
* to be serialized or a designate replacement may be specified, by the
|
||||
* writeReplace and readResolve methods, respectively. Any
|
||||
* serialPersistentFields field declaration is ignored. Documenting serializable
|
||||
* fields and data for record classes is unnecessary, since there is no variation
|
||||
* in the serial form, other than whether a substitute or replacement object is
|
||||
* used. The serialVersionUID of a record class is 0L unless explicitly
|
||||
* declared. The requirement for matching serialVersionUID values is waived for
|
||||
* record classes.
|
||||
*
|
||||
* @author Mike Warres
|
||||
* @author Roger Riggs
|
||||
* @see java.io.DataInput
|
||||
@ -2047,6 +2082,11 @@ public class ObjectInputStream
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
private static boolean isRecord(Class<?> cls) {
|
||||
return cls.isRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and returns "ordinary" (i.e., not a String, Class,
|
||||
* ObjectStreamClass, array, or enum constant) object, or null if object's
|
||||
@ -2085,7 +2125,12 @@ public class ObjectInputStream
|
||||
handles.markException(passHandle, resolveEx);
|
||||
}
|
||||
|
||||
if (desc.isExternalizable()) {
|
||||
final boolean isRecord = cl != null && isRecord(cl) ? true : false;
|
||||
if (isRecord) {
|
||||
assert obj == null;
|
||||
obj = readRecord(desc);
|
||||
handles.setObject(passHandle, obj);
|
||||
} else if (desc.isExternalizable()) {
|
||||
readExternalData((Externalizable) obj, desc);
|
||||
} else {
|
||||
readSerialData(obj, desc);
|
||||
@ -2171,6 +2216,43 @@ public class ObjectInputStream
|
||||
*/
|
||||
}
|
||||
|
||||
/** Reads a record. */
|
||||
private Object readRecord(ObjectStreamClass desc) throws IOException {
|
||||
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
|
||||
if (slots.length != 1) {
|
||||
// skip any superclass stream field values
|
||||
for (int i = 0; i < slots.length-1; i++) {
|
||||
ObjectStreamClass slotDesc = slots[i].desc;
|
||||
if (slots[i].hasData) {
|
||||
defaultReadFields(null, slotDesc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FieldValues fieldValues = defaultReadFields(null, desc);
|
||||
|
||||
// retrieve the canonical constructor
|
||||
MethodHandle ctrMH = desc.getRecordConstructor();
|
||||
|
||||
// bind the stream field values
|
||||
ctrMH = RecordSupport.bindCtrValues(ctrMH, desc, fieldValues);
|
||||
|
||||
try {
|
||||
return ctrMH.invoke();
|
||||
} catch (Exception e) {
|
||||
InvalidObjectException ioe = new InvalidObjectException(e.getMessage());
|
||||
ioe.initCause(e);
|
||||
throw ioe;
|
||||
} catch (Error e) {
|
||||
throw e;
|
||||
} catch (Throwable t) {
|
||||
ObjectStreamException ose = new InvalidObjectException(
|
||||
"ReflectiveOperationException during deserialization");
|
||||
ose.initCause(t);
|
||||
throw ose;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads (or attempts to skip, if obj is null or is tagged with a
|
||||
* ClassNotFoundException) instance data for each serializable class of
|
||||
@ -2317,7 +2399,7 @@ public class ObjectInputStream
|
||||
}
|
||||
}
|
||||
|
||||
private class FieldValues {
|
||||
/*package-private*/ class FieldValues {
|
||||
final byte[] primValues;
|
||||
final Object[] objValues;
|
||||
|
||||
|
@ -150,6 +150,10 @@ import sun.reflect.misc.ReflectUtil;
|
||||
* defaultWriteObject and writeFields initially terminate any existing
|
||||
* block-data record.
|
||||
*
|
||||
* @implSpec
|
||||
* Records are serialized differently than ordinary serializable or externalizable
|
||||
* objects, see <a href="ObjectInputStream.html#record-serialization">record serialization</a>.
|
||||
*
|
||||
* @author Mike Warres
|
||||
* @author Roger Riggs
|
||||
* @see java.io.DataOutput
|
||||
@ -1431,7 +1435,10 @@ public class ObjectOutputStream
|
||||
bout.writeByte(TC_OBJECT);
|
||||
writeClassDesc(desc, false);
|
||||
handles.assign(unshared ? null : obj);
|
||||
if (desc.isExternalizable() && !desc.isProxy()) {
|
||||
|
||||
if (desc.isRecord()) {
|
||||
writeRecordData(obj, desc);
|
||||
} else if (desc.isExternalizable() && !desc.isProxy()) {
|
||||
writeExternalData((Externalizable) obj);
|
||||
} else {
|
||||
writeSerialData(obj, desc);
|
||||
@ -1475,6 +1482,21 @@ public class ObjectOutputStream
|
||||
curPut = oldPut;
|
||||
}
|
||||
|
||||
/** Writes the record component values for the given record object. */
|
||||
@SuppressWarnings("preview")
|
||||
private void writeRecordData(Object obj, ObjectStreamClass desc)
|
||||
throws IOException
|
||||
{
|
||||
assert obj.getClass().isRecord();
|
||||
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
|
||||
if (slots.length != 1) {
|
||||
throw new InvalidClassException(
|
||||
"expected a single record slot length, but found: " + slots.length);
|
||||
}
|
||||
|
||||
defaultWriteFields(obj, desc); // #### seems unnecessary to use the accessors
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes instance data for each serializable class of given object, from
|
||||
* superclass to subclass.
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package java.io;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
@ -32,6 +34,7 @@ import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.RecordComponent;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
@ -44,6 +47,8 @@ import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PermissionCollection;
|
||||
import java.security.Permissions;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -123,6 +128,8 @@ public class ObjectStreamClass implements Serializable {
|
||||
private boolean isProxy;
|
||||
/** true if represents enum type */
|
||||
private boolean isEnum;
|
||||
/** true if represents record type */
|
||||
private boolean isRecord;
|
||||
/** true if represented class implements Serializable */
|
||||
private boolean serializable;
|
||||
/** true if represented class implements Externalizable */
|
||||
@ -184,6 +191,8 @@ public class ObjectStreamClass implements Serializable {
|
||||
|
||||
/** serialization-appropriate constructor, or null if none */
|
||||
private Constructor<?> cons;
|
||||
/** record canonical constructor, or null */
|
||||
private MethodHandle canonicalCtr;
|
||||
/** protection domains that need to be checked when calling the constructor */
|
||||
private ProtectionDomain[] domains;
|
||||
|
||||
@ -261,6 +270,9 @@ public class ObjectStreamClass implements Serializable {
|
||||
public long getSerialVersionUID() {
|
||||
// REMIND: synchronize instead of relying on volatile?
|
||||
if (suid == null) {
|
||||
if (isRecord)
|
||||
return 0L;
|
||||
|
||||
suid = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Long>() {
|
||||
public Long run() {
|
||||
@ -467,6 +479,11 @@ public class ObjectStreamClass implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
private static boolean isRecord(Class<?> cls) {
|
||||
return cls.isRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates local class descriptor representing given class.
|
||||
*/
|
||||
@ -475,6 +492,7 @@ public class ObjectStreamClass implements Serializable {
|
||||
name = cl.getName();
|
||||
isProxy = Proxy.isProxyClass(cl);
|
||||
isEnum = Enum.class.isAssignableFrom(cl);
|
||||
isRecord = isRecord(cl);
|
||||
serializable = Serializable.class.isAssignableFrom(cl);
|
||||
externalizable = Externalizable.class.isAssignableFrom(cl);
|
||||
|
||||
@ -505,7 +523,9 @@ public class ObjectStreamClass implements Serializable {
|
||||
fields = NO_FIELDS;
|
||||
}
|
||||
|
||||
if (externalizable) {
|
||||
if (isRecord) {
|
||||
canonicalCtr = canonicalRecordCtr(cl);
|
||||
} else if (externalizable) {
|
||||
cons = getExternalizableConstructor(cl);
|
||||
} else {
|
||||
cons = getSerializableConstructor(cl);
|
||||
@ -542,14 +562,18 @@ public class ObjectStreamClass implements Serializable {
|
||||
if (deserializeEx == null) {
|
||||
if (isEnum) {
|
||||
deserializeEx = new ExceptionInfo(name, "enum type");
|
||||
} else if (cons == null) {
|
||||
} else if (cons == null && !isRecord) {
|
||||
deserializeEx = new ExceptionInfo(name, "no valid constructor");
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
if (fields[i].getField() == null) {
|
||||
defaultSerializeEx = new ExceptionInfo(
|
||||
name, "unmatched serializable field(s) declared");
|
||||
if (isRecord && canonicalCtr == null) {
|
||||
deserializeEx = new ExceptionInfo(name, "record canonical constructor not found");
|
||||
} else {
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
if (fields[i].getField() == null) {
|
||||
defaultSerializeEx = new ExceptionInfo(
|
||||
name, "unmatched serializable field(s) declared");
|
||||
}
|
||||
}
|
||||
}
|
||||
initialized = true;
|
||||
@ -682,7 +706,7 @@ public class ObjectStreamClass implements Serializable {
|
||||
}
|
||||
|
||||
if (model.serializable == osc.serializable &&
|
||||
!cl.isArray() &&
|
||||
!cl.isArray() && !isRecord(cl) &&
|
||||
suid != osc.getSerialVersionUID()) {
|
||||
throw new InvalidClassException(osc.name,
|
||||
"local class incompatible: " +
|
||||
@ -714,6 +738,10 @@ public class ObjectStreamClass implements Serializable {
|
||||
}
|
||||
|
||||
this.cl = cl;
|
||||
if (cl != null) {
|
||||
this.isRecord = isRecord(cl);
|
||||
this.canonicalCtr = osc.canonicalCtr;
|
||||
}
|
||||
this.resolveEx = resolveEx;
|
||||
this.superDesc = superDesc;
|
||||
name = model.name;
|
||||
@ -739,12 +767,14 @@ public class ObjectStreamClass implements Serializable {
|
||||
deserializeEx = localDesc.deserializeEx;
|
||||
}
|
||||
domains = localDesc.domains;
|
||||
assert isRecord(cl) ? localDesc.cons == null : true;
|
||||
cons = localDesc.cons;
|
||||
}
|
||||
|
||||
fieldRefl = getReflector(fields, localDesc);
|
||||
// reassign to matched fields so as to reflect local unshared settings
|
||||
fields = fieldRefl.getFields();
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@ -966,6 +996,15 @@ public class ObjectStreamClass implements Serializable {
|
||||
return isEnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if class descriptor represents a record type, false
|
||||
* otherwise.
|
||||
*/
|
||||
boolean isRecord() {
|
||||
requireInitialized();
|
||||
return isRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if represented class implements Externalizable, false
|
||||
* otherwise.
|
||||
@ -1518,6 +1557,37 @@ public class ObjectStreamClass implements Serializable {
|
||||
return reflFactory.newConstructorForSerialization(cl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the canonical constructor for the given record class, or null if
|
||||
* the not found ( which should never happen for correctly generated record
|
||||
* classes ).
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
private static MethodHandle canonicalRecordCtr(Class<?> cls) {
|
||||
assert isRecord(cls) : "Expected record, got: " + cls;
|
||||
PrivilegedAction<MethodHandle> pa = () -> {
|
||||
Class<?>[] paramTypes = Arrays.stream(cls.getRecordComponents())
|
||||
.map(RecordComponent::getType)
|
||||
.toArray(Class<?>[]::new);
|
||||
try {
|
||||
Constructor<?> ctr = cls.getConstructor(paramTypes);
|
||||
ctr.setAccessible(true);
|
||||
return MethodHandles.lookup().unreflectConstructor(ctr);
|
||||
} catch (IllegalAccessException | NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return AccessController.doPrivileged(pa);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the canonical constructor, if the local class equivalent of this
|
||||
* stream class descriptor is a record class, otherwise null.
|
||||
*/
|
||||
MethodHandle getRecordConstructor() {
|
||||
return canonicalCtr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns non-static, non-abstract method with given signature provided it
|
||||
* is defined by or accessible (via inheritance) by the given class, or
|
||||
@ -1641,12 +1711,16 @@ public class ObjectStreamClass implements Serializable {
|
||||
private static ObjectStreamField[] getSerialFields(Class<?> cl)
|
||||
throws InvalidClassException
|
||||
{
|
||||
if (!Serializable.class.isAssignableFrom(cl))
|
||||
return NO_FIELDS;
|
||||
|
||||
ObjectStreamField[] fields;
|
||||
if (Serializable.class.isAssignableFrom(cl) &&
|
||||
!Externalizable.class.isAssignableFrom(cl) &&
|
||||
if (isRecord(cl)) {
|
||||
fields = getDefaultSerialFields(cl);
|
||||
Arrays.sort(fields);
|
||||
} else if (!Externalizable.class.isAssignableFrom(cl) &&
|
||||
!Proxy.isProxyClass(cl) &&
|
||||
!cl.isInterface())
|
||||
{
|
||||
!cl.isInterface()) {
|
||||
if ((fields = getDeclaredSerialFields(cl)) == null) {
|
||||
fields = getDefaultSerialFields(cl);
|
||||
}
|
||||
@ -2438,4 +2512,115 @@ public class ObjectStreamClass implements Serializable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Record specific support for retrieving and binding stream field values. */
|
||||
static final class RecordSupport {
|
||||
|
||||
/** Binds the given stream field values to the given method handle. */
|
||||
@SuppressWarnings("preview")
|
||||
static MethodHandle bindCtrValues(MethodHandle ctrMH,
|
||||
ObjectStreamClass desc,
|
||||
ObjectInputStream.FieldValues fieldValues) {
|
||||
RecordComponent[] recordComponents;
|
||||
try {
|
||||
Class<?> cls = desc.forClass();
|
||||
PrivilegedExceptionAction<RecordComponent[]> pa = cls::getRecordComponents;
|
||||
recordComponents = AccessController.doPrivileged(pa);
|
||||
} catch (PrivilegedActionException e) {
|
||||
throw new InternalError(e.getCause());
|
||||
}
|
||||
|
||||
Object[] args = new Object[recordComponents.length];
|
||||
for (int i = 0; i < recordComponents.length; i++) {
|
||||
String name = recordComponents[i].getName();
|
||||
Class<?> type= recordComponents[i].getType();
|
||||
Object o = streamFieldValue(name, type, desc, fieldValues);
|
||||
args[i] = o;
|
||||
}
|
||||
|
||||
return MethodHandles.insertArguments(ctrMH, 0, args);
|
||||
}
|
||||
|
||||
/** Returns the number of primitive fields for the given descriptor. */
|
||||
private static int numberPrimValues(ObjectStreamClass desc) {
|
||||
ObjectStreamField[] fields = desc.getFields();
|
||||
int primValueCount = 0;
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
if (fields[i].isPrimitive())
|
||||
primValueCount++;
|
||||
else
|
||||
break; // can be no more
|
||||
}
|
||||
return primValueCount;
|
||||
}
|
||||
|
||||
/** Returns the default value for the given type. */
|
||||
private static Object defaultValueFor(Class<?> pType) {
|
||||
if (pType == Integer.TYPE)
|
||||
return 0;
|
||||
else if (pType == Byte.TYPE)
|
||||
return (byte)0;
|
||||
else if (pType == Long.TYPE)
|
||||
return 0L;
|
||||
else if (pType == Float.TYPE)
|
||||
return 0.0f;
|
||||
else if (pType == Double.TYPE)
|
||||
return 0.0d;
|
||||
else if (pType == Short.TYPE)
|
||||
return (short)0;
|
||||
else if (pType == Character.TYPE)
|
||||
return '\u0000';
|
||||
else if (pType == Boolean.TYPE)
|
||||
return false;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the stream field value for the given name. The default value
|
||||
* for the given type is returned if the field value is absent.
|
||||
*/
|
||||
private static Object streamFieldValue(String pName,
|
||||
Class<?> pType,
|
||||
ObjectStreamClass desc,
|
||||
ObjectInputStream.FieldValues fieldValues) {
|
||||
ObjectStreamField[] fields = desc.getFields();
|
||||
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
ObjectStreamField f = fields[i];
|
||||
String fName = f.getName();
|
||||
if (!fName.equals(pName))
|
||||
continue;
|
||||
|
||||
Class<?> fType = f.getField().getType();
|
||||
if (!pType.isAssignableFrom(fType))
|
||||
throw new InternalError(fName + " unassignable, pType:" + pType + ", fType:" + fType);
|
||||
|
||||
if (f.isPrimitive()) {
|
||||
if (pType == Integer.TYPE)
|
||||
return Bits.getInt(fieldValues.primValues, f.getOffset());
|
||||
else if (fType == Byte.TYPE)
|
||||
return fieldValues.primValues[f.getOffset()];
|
||||
else if (fType == Long.TYPE)
|
||||
return Bits.getLong(fieldValues.primValues, f.getOffset());
|
||||
else if (fType == Float.TYPE)
|
||||
return Bits.getFloat(fieldValues.primValues, f.getOffset());
|
||||
else if (fType == Double.TYPE)
|
||||
return Bits.getDouble(fieldValues.primValues, f.getOffset());
|
||||
else if (fType == Short.TYPE)
|
||||
return Bits.getShort(fieldValues.primValues, f.getOffset());
|
||||
else if (fType == Character.TYPE)
|
||||
return Bits.getChar(fieldValues.primValues, f.getOffset());
|
||||
else if (fType == Boolean.TYPE)
|
||||
return Bits.getBoolean(fieldValues.primValues, f.getOffset());
|
||||
else
|
||||
throw new InternalError("Unexpected type: " + fType);
|
||||
} else { // reference
|
||||
return fieldValues.objValues[i - numberPrimValues(desc)];
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValueFor(pType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.RecordComponent;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.constant.Constable;
|
||||
@ -2259,6 +2260,68 @@ public final class Class<T> implements java.io.Serializable,
|
||||
return copyFields(privateGetDeclaredFields(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>records</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 RecordComponent} objects reflecting all the
|
||||
* declared record components of the record represented by this {@code Class} object.
|
||||
* The components are returned in the same order that they are declared in the
|
||||
* record header.
|
||||
*
|
||||
* @return The array of {@code RecordComponent} objects representing all the
|
||||
* record components of this record. The array is empty if this class
|
||||
* is not a record, or if this class is a record with no components.
|
||||
* @throws SecurityException
|
||||
* If a security manager, <i>s</i>, is present and any of the
|
||||
* following conditions is met:
|
||||
*
|
||||
* <ul>
|
||||
*
|
||||
* <li> the caller's class loader is not the same as the
|
||||
* class loader of this class and invocation of
|
||||
* {@link SecurityManager#checkPermission
|
||||
* s.checkPermission} method with
|
||||
* {@code RuntimePermission("accessDeclaredMembers")}
|
||||
* denies access to the declared methods within this class
|
||||
*
|
||||
* <li> the caller's class loader is not the same as or an
|
||||
* ancestor of the class loader for the current class and
|
||||
* invocation of {@link SecurityManager#checkPackageAccess
|
||||
* s.checkPackageAccess()} denies access to the package
|
||||
* of this class
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* @jls 8.10 Record Types
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SuppressWarnings("preview")
|
||||
@CallerSensitive
|
||||
public RecordComponent[] getRecordComponents() {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
|
||||
}
|
||||
if (isPrimitive() || isArray()) {
|
||||
return new RecordComponent[0];
|
||||
}
|
||||
Object[] recordComponents = getRecordComponents0();
|
||||
if (recordComponents == null || recordComponents.length == 0) {
|
||||
return new RecordComponent[0];
|
||||
}
|
||||
RecordComponent[] result = new RecordComponent[recordComponents.length];
|
||||
for (int i = 0; i < recordComponents.length; i++) {
|
||||
result[i] = (RecordComponent)recordComponents[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing {@code Method} objects reflecting all the
|
||||
@ -3417,6 +3480,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
private native Method[] getDeclaredMethods0(boolean publicOnly);
|
||||
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
|
||||
private native Class<?>[] getDeclaredClasses0();
|
||||
private native Object[] getRecordComponents0();
|
||||
private native boolean isRecord0();
|
||||
|
||||
/**
|
||||
* Helper method to get the method name from arguments.
|
||||
@ -3525,6 +3590,29 @@ public final class Class<T> implements java.io.Serializable,
|
||||
this.getSuperclass() == java.lang.Enum.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>records</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 class is a record class.
|
||||
* It returns {@code false} otherwise. Note that class {@link Record} is not a
|
||||
* record type and thus invoking this method on class {@link java.lang.Record}
|
||||
* returns {@code false}.
|
||||
*
|
||||
* @return true if and only if this class is a record class
|
||||
* @jls 8.10 Record Types
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
public boolean isRecord() {
|
||||
return isRecord0();
|
||||
}
|
||||
|
||||
// Fetches the factory for reflective objects
|
||||
private static ReflectionFactory getReflectionFactory() {
|
||||
if (reflectionFactory == null) {
|
||||
|
154
src/java.base/share/classes/java/lang/Record.java
Normal file
154
src/java.base/share/classes/java/lang/Record.java
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 java.lang;
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This class is associated with <i>records</i>, a preview
|
||||
* feature of the Java language. Programs can only use this
|
||||
* class when preview features are enabled. Preview features
|
||||
* may be removed in a future release, or upgraded to permanent
|
||||
* features of the Java language.}
|
||||
*
|
||||
* This is the common base class of all Java language record classes.
|
||||
*
|
||||
* <p>More information about records, including descriptions of the
|
||||
* implicitly declared methods synthesized by the compiler, can be
|
||||
* found in section 8.10 of
|
||||
* <cite>The Java™ Language Specification</cite>.
|
||||
*
|
||||
* <p>A <em>record class</em> is a shallowly immutable, transparent carrier for
|
||||
* a fixed set of values, called the <em>record components</em>. The Java™
|
||||
* language provides concise syntax for declaring record classes, whereby the
|
||||
* record components are declared in the record header. The list of record
|
||||
* components declared in the record header form the <em>record descriptor</em>.
|
||||
*
|
||||
* <p>A record class has the following mandated members: a public <em>canonical
|
||||
* constructor</em>, whose descriptor is the same as the record descriptor;
|
||||
* a private final field corresponding to each component, whose name and
|
||||
* type are the same as that of the component; a public accessor method
|
||||
* corresponding to each component, whose name and return type are the same as
|
||||
* that of the component. If not explicitly declared in the body of the record,
|
||||
* implicit implementations for these members are provided.
|
||||
*
|
||||
* <p>The implicit declaration of the canonical constructor initializes the
|
||||
* component fields from the corresponding constructor arguments. The implicit
|
||||
* declaration of the accessor methods returns the value of the corresponding
|
||||
* component field. The implicit declaration of the {@link Object#equals(Object)},
|
||||
* {@link Object#hashCode()}, and {@link Object#toString()} methods are derived
|
||||
* from all of the component fields.
|
||||
*
|
||||
* <p>The primary reasons to provide an explicit declaration for the
|
||||
* canonical constructor or accessor methods are to validate constructor
|
||||
* arguments, perform defensive copies on mutable components, or normalize groups
|
||||
* of components (such as reducing a rational number to lowest terms.)
|
||||
*
|
||||
* <p>For all record classes, the following invariant must hold: if a record R's
|
||||
* components are {@code c1, c2, ... cn}, then if a record instance is copied
|
||||
* as follows:
|
||||
* <pre>
|
||||
* R copy = new R(r.c1(), r.c2(), ..., r.cn());
|
||||
* </pre>
|
||||
* then it must be the case that {@code r.equals(copy)}.
|
||||
*
|
||||
* @apiNote
|
||||
* A record class that {@code implements} {@link java.io.Serializable} is said
|
||||
* to be a <i>serializable record</i>. Serializable records are serialized and
|
||||
* deserialized differently than ordinary serializable objects. During
|
||||
* deserialization the record's canonical constructor is invoked to construct
|
||||
* the record object. Certain serialization-related methods, such as readObject
|
||||
* and writeObject, are ignored for serializable records. More information about
|
||||
* serializable records can be found in
|
||||
* <a href="{@docRoot}/java.base/java/io/ObjectInputStream.html#record-serialization">record serialization</a>.
|
||||
*
|
||||
* @jls 8.10 Record Types
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=true)
|
||||
public abstract class Record {
|
||||
/**
|
||||
* Indicates whether some other object is "equal to" this one. In addition
|
||||
* to the general contract of {@link Object#equals(Object)},
|
||||
* record classes must further participate in the invariant that when
|
||||
* a record instance is "copied" by passing the result of the record component
|
||||
* accessor methods to the canonical constructor, as follows:
|
||||
* <pre>
|
||||
* R copy = new R(r.c1(), r.c2(), ..., r.cn());
|
||||
* </pre>
|
||||
* then it must be the case that {@code r.equals(copy)}.
|
||||
*
|
||||
* @implSpec
|
||||
* The implicitly provided implementation returns {@code true} if and
|
||||
* only if the argument is an instance of the same record type as this object,
|
||||
* and each component of this record is equal to the corresponding component
|
||||
* of the argument, according to {@link java.util.Objects#equals(Object,Object)}
|
||||
* for components whose types are reference types, and according to the semantics
|
||||
* of the {@code equals} method on the corresponding primitive wrapper type.
|
||||
*
|
||||
* @see java.util.Objects#equals(Object,Object)
|
||||
*
|
||||
* @param obj the reference object with which to compare.
|
||||
* @return {@code true} if this object is the same as the obj
|
||||
* argument; {@code false} otherwise.
|
||||
*/
|
||||
@Override
|
||||
public abstract boolean equals(Object obj);
|
||||
|
||||
/**
|
||||
* Obeys the general contract of {@link Object#hashCode Object.hashCode}.
|
||||
*
|
||||
* @implSpec
|
||||
* The implicitly provided implementation returns a hash code value derived
|
||||
* by combining the hash code value for all the components, according to
|
||||
* {@link Object#hashCode()} for components whose types are reference types,
|
||||
* or the primitive wrapper hash code for components whose types are primitive
|
||||
* types.
|
||||
*
|
||||
* @see Object#hashCode()
|
||||
*
|
||||
* @return a hash code value for this object.
|
||||
*/
|
||||
@Override
|
||||
public abstract int hashCode();
|
||||
|
||||
/**
|
||||
* Obeys the general contract of {@link Object#toString Object.toString}.
|
||||
*
|
||||
* @implSpec
|
||||
* The implicitly provided implementation returns a string that is derived
|
||||
* from the name of the record class and the names and string representations
|
||||
* of all the components, according to {@link Object#toString()} for components
|
||||
* whose types are reference types, and the primitive wrapper {@code toString}
|
||||
* method for components whose types are primitive types.
|
||||
*
|
||||
* @see Object#toString()
|
||||
*
|
||||
* @return a string representation of the object.
|
||||
*/
|
||||
@Override
|
||||
public abstract String toString();
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2019, 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
|
||||
@ -114,5 +114,25 @@ public enum ElementType {
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
MODULE
|
||||
MODULE,
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This constant is associated with <i>records</i>, a preview
|
||||
* feature of the Java language. Programs can only use this
|
||||
* constant when preview features are enabled. Preview features
|
||||
* may be removed in a future release, or upgraded to permanent
|
||||
* features of the Java language.}
|
||||
*
|
||||
* Record component
|
||||
*
|
||||
* @jls 8.10.3 Record Members
|
||||
* @jls 9.7.4 Where Annotations May Appear
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=true)
|
||||
RECORD_COMPONENT;
|
||||
}
|
||||
|
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 java.lang.reflect;
|
||||
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import sun.reflect.annotation.AnnotationParser;
|
||||
import sun.reflect.annotation.TypeAnnotation;
|
||||
import sun.reflect.annotation.TypeAnnotationParser;
|
||||
import sun.reflect.generics.factory.CoreReflectionFactory;
|
||||
import sun.reflect.generics.factory.GenericsFactory;
|
||||
import sun.reflect.generics.repository.FieldRepository;
|
||||
import sun.reflect.generics.scope.ClassScope;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This class is associated with <i>records</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.}
|
||||
*
|
||||
* A {@code RecordComponent} provides information about, and dynamic access to, a
|
||||
* component of a record class.
|
||||
*
|
||||
* @see Class#getRecordComponents()
|
||||
* @see java.lang.Record
|
||||
* @jls 8.10 Record Types
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
public final class RecordComponent implements AnnotatedElement {
|
||||
// declaring class
|
||||
private Class<?> clazz;
|
||||
private String name;
|
||||
private Class<?> type;
|
||||
private Method accessor;
|
||||
private String signature;
|
||||
// generic info repository; lazily initialized
|
||||
private transient FieldRepository genericInfo;
|
||||
private byte[] annotations;
|
||||
private byte[] typeAnnotations;
|
||||
@SuppressWarnings("preview")
|
||||
private RecordComponent root;
|
||||
|
||||
// only the JVM can create record components
|
||||
private RecordComponent() {}
|
||||
|
||||
/**
|
||||
* Returns the name of this record component.
|
||||
*
|
||||
* @return the name of this record component
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Class} that identifies the declared type for this
|
||||
* record component.
|
||||
*
|
||||
* @return a {@code Class} identifying the declared type of the component
|
||||
* represented by this record component
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code String} that describes the generic type signature for
|
||||
* this record component.
|
||||
*
|
||||
* @return a {@code String} that describes the generic type signature for
|
||||
* this record component
|
||||
*
|
||||
* @jvms 4.7.9.1 Signatures
|
||||
*/
|
||||
public String getGenericSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Type} object that represents the declared type for
|
||||
* this record component.
|
||||
*
|
||||
* <p>If the declared type of the record component is a parameterized type,
|
||||
* the {@code Type} object returned reflects the actual type arguments used
|
||||
* in the source code.
|
||||
*
|
||||
* <p>If the type of the underlying record component is a type variable or a
|
||||
* parameterized type, it is created. Otherwise, it is resolved.
|
||||
*
|
||||
* @return a {@code Type} object that represents the declared type for
|
||||
* this record component
|
||||
* @throws GenericSignatureFormatError if the generic record component
|
||||
* signature does not conform to the format specified in
|
||||
* <cite>The Java™ Virtual Machine Specification</cite>
|
||||
* @throws TypeNotPresentException if the generic type
|
||||
* signature of the underlying record component refers to a non-existent
|
||||
* type declaration
|
||||
* @throws MalformedParameterizedTypeException if the generic
|
||||
* signature of the underlying record component refers to a parameterized
|
||||
* type that cannot be instantiated for any reason
|
||||
*/
|
||||
public Type getGenericType() {
|
||||
if (getGenericSignature() != null)
|
||||
return getGenericInfo().getGenericType();
|
||||
else
|
||||
return getType();
|
||||
}
|
||||
|
||||
// Accessor for generic info repository
|
||||
private FieldRepository getGenericInfo() {
|
||||
// lazily initialize repository if necessary
|
||||
if (genericInfo == null) {
|
||||
// create and cache generic info repository
|
||||
genericInfo = FieldRepository.make(getGenericSignature(), getFactory());
|
||||
}
|
||||
return genericInfo; //return cached repository
|
||||
}
|
||||
|
||||
// Accessor for factory
|
||||
private GenericsFactory getFactory() {
|
||||
Class<?> c = getDeclaringRecord();
|
||||
// create scope and factory
|
||||
return CoreReflectionFactory.make(c, ClassScope.make(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@code AnnotatedType} object that represents the use of a type to specify
|
||||
* the declared type of this record component.
|
||||
*
|
||||
* @return an object representing the declared type of this record component
|
||||
*/
|
||||
public AnnotatedType getAnnotatedType() {
|
||||
return TypeAnnotationParser.buildAnnotatedType(typeAnnotations,
|
||||
SharedSecrets.getJavaLangAccess().
|
||||
getConstantPool(getDeclaringRecord()),
|
||||
this,
|
||||
getDeclaringRecord(),
|
||||
getGenericType(),
|
||||
TypeAnnotation.TypeAnnotationTarget.FIELD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code Method} that represents the accessor for this record
|
||||
* component.
|
||||
*
|
||||
* @return a {@code Method} that represents the accessor for this record
|
||||
* component
|
||||
*/
|
||||
public Method getAccessor() {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws NullPointerException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
|
||||
Objects.requireNonNull(annotationClass);
|
||||
return annotationClass.cast(declaredAnnotations().get(annotationClass));
|
||||
}
|
||||
|
||||
private transient volatile Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
|
||||
|
||||
private Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
|
||||
Map<Class<? extends Annotation>, Annotation> declAnnos;
|
||||
if ((declAnnos = declaredAnnotations) == null) {
|
||||
synchronized (this) {
|
||||
if ((declAnnos = declaredAnnotations) == null) {
|
||||
@SuppressWarnings("preview")
|
||||
RecordComponent root = this.root;
|
||||
if (root != null) {
|
||||
declAnnos = root.declaredAnnotations();
|
||||
} else {
|
||||
declAnnos = AnnotationParser.parseAnnotations(
|
||||
annotations,
|
||||
SharedSecrets.getJavaLangAccess()
|
||||
.getConstantPool(getDeclaringRecord()),
|
||||
getDeclaringRecord());
|
||||
}
|
||||
declaredAnnotations = declAnnos;
|
||||
}
|
||||
}
|
||||
}
|
||||
return declAnnos;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Annotation[] getAnnotations() {
|
||||
return getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Annotation[] getDeclaredAnnotations() { return AnnotationParser.toArray(declaredAnnotations()); }
|
||||
|
||||
/**
|
||||
* Returns a string describing this record component. The format is
|
||||
* the record component type, followed by a space, followed by the name
|
||||
* of the record component.
|
||||
* For example:
|
||||
* <pre>
|
||||
* String name
|
||||
* int age
|
||||
* </pre>
|
||||
*
|
||||
* @return a string describing this record component
|
||||
*/
|
||||
public String toString() {
|
||||
return (getType().getTypeName() + " " + getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record class which declares this record component.
|
||||
*
|
||||
* @return The record class declaring this record component.
|
||||
*/
|
||||
public Class<?> getDeclaringRecord() {
|
||||
return clazz;
|
||||
}
|
||||
}
|
375
src/java.base/share/classes/java/lang/runtime/ObjectMethods.java
Normal file
375
src/java.base/share/classes/java/lang/runtime/ObjectMethods.java
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2019, 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 java.lang.runtime;
|
||||
|
||||
import java.lang.invoke.ConstantCallSite;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.TypeDescriptor;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This class is associated with <i>records</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.}
|
||||
*
|
||||
* Bootstrap methods for state-driven implementations of core methods,
|
||||
* including {@link Object#equals(Object)}, {@link Object#hashCode()}, and
|
||||
* {@link Object#toString()}. These methods may be used, for example, by
|
||||
* Java™ compiler implementations to implement the bodies of {@link Object}
|
||||
* methods for record classes.
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
public class ObjectMethods {
|
||||
|
||||
private ObjectMethods() { }
|
||||
|
||||
private static final MethodType DESCRIPTOR_MT = MethodType.methodType(MethodType.class);
|
||||
private static final MethodType NAMES_MT = MethodType.methodType(List.class);
|
||||
private static final MethodHandle FALSE = MethodHandles.constant(boolean.class, false);
|
||||
private static final MethodHandle TRUE = MethodHandles.constant(boolean.class, true);
|
||||
private static final MethodHandle ZERO = MethodHandles.constant(int.class, 0);
|
||||
private static final MethodHandle CLASS_IS_INSTANCE;
|
||||
private static final MethodHandle OBJECT_EQUALS;
|
||||
private static final MethodHandle OBJECTS_EQUALS;
|
||||
private static final MethodHandle OBJECTS_HASHCODE;
|
||||
private static final MethodHandle OBJECTS_TOSTRING;
|
||||
private static final MethodHandle OBJECT_EQ;
|
||||
private static final MethodHandle OBJECT_HASHCODE;
|
||||
private static final MethodHandle OBJECT_TO_STRING;
|
||||
private static final MethodHandle STRING_FORMAT;
|
||||
private static final MethodHandle HASH_COMBINER;
|
||||
|
||||
private static final HashMap<Class<?>, MethodHandle> primitiveEquals = new HashMap<>();
|
||||
private static final HashMap<Class<?>, MethodHandle> primitiveHashers = new HashMap<>();
|
||||
private static final HashMap<Class<?>, MethodHandle> primitiveToString = new HashMap<>();
|
||||
|
||||
static {
|
||||
try {
|
||||
@SuppressWarnings("preview")
|
||||
Class<ObjectMethods> OBJECT_METHODS_CLASS = ObjectMethods.class;
|
||||
MethodHandles.Lookup publicLookup = MethodHandles.publicLookup();
|
||||
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
ClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
||||
@Override public ClassLoader run() { return ClassLoader.getPlatformClassLoader(); }
|
||||
});
|
||||
|
||||
CLASS_IS_INSTANCE = publicLookup.findVirtual(Class.class, "isInstance",
|
||||
MethodType.methodType(boolean.class, Object.class));
|
||||
OBJECT_EQUALS = publicLookup.findVirtual(Object.class, "equals",
|
||||
MethodType.methodType(boolean.class, Object.class));
|
||||
OBJECT_HASHCODE = publicLookup.findVirtual(Object.class, "hashCode",
|
||||
MethodType.fromMethodDescriptorString("()I", loader));
|
||||
OBJECT_TO_STRING = publicLookup.findVirtual(Object.class, "toString",
|
||||
MethodType.methodType(String.class));
|
||||
STRING_FORMAT = publicLookup.findStatic(String.class, "format",
|
||||
MethodType.methodType(String.class, String.class, Object[].class));
|
||||
OBJECTS_EQUALS = publicLookup.findStatic(Objects.class, "equals",
|
||||
MethodType.methodType(boolean.class, Object.class, Object.class));
|
||||
OBJECTS_HASHCODE = publicLookup.findStatic(Objects.class, "hashCode",
|
||||
MethodType.methodType(int.class, Object.class));
|
||||
OBJECTS_TOSTRING = publicLookup.findStatic(Objects.class, "toString",
|
||||
MethodType.methodType(String.class, Object.class));
|
||||
|
||||
OBJECT_EQ = lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
|
||||
MethodType.methodType(boolean.class, Object.class, Object.class));
|
||||
HASH_COMBINER = lookup.findStatic(OBJECT_METHODS_CLASS, "hashCombiner",
|
||||
MethodType.fromMethodDescriptorString("(II)I", loader));
|
||||
|
||||
primitiveEquals.put(byte.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
|
||||
MethodType.fromMethodDescriptorString("(BB)Z", loader)));
|
||||
primitiveEquals.put(short.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
|
||||
MethodType.fromMethodDescriptorString("(SS)Z", loader)));
|
||||
primitiveEquals.put(char.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
|
||||
MethodType.fromMethodDescriptorString("(CC)Z", loader)));
|
||||
primitiveEquals.put(int.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
|
||||
MethodType.fromMethodDescriptorString("(II)Z", loader)));
|
||||
primitiveEquals.put(long.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
|
||||
MethodType.fromMethodDescriptorString("(JJ)Z", loader)));
|
||||
primitiveEquals.put(float.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
|
||||
MethodType.fromMethodDescriptorString("(FF)Z", loader)));
|
||||
primitiveEquals.put(double.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
|
||||
MethodType.fromMethodDescriptorString("(DD)Z", loader)));
|
||||
primitiveEquals.put(boolean.class, lookup.findStatic(OBJECT_METHODS_CLASS, "eq",
|
||||
MethodType.fromMethodDescriptorString("(ZZ)Z", loader)));
|
||||
|
||||
primitiveHashers.put(byte.class, lookup.findStatic(Byte.class, "hashCode",
|
||||
MethodType.fromMethodDescriptorString("(B)I", loader)));
|
||||
primitiveHashers.put(short.class, lookup.findStatic(Short.class, "hashCode",
|
||||
MethodType.fromMethodDescriptorString("(S)I", loader)));
|
||||
primitiveHashers.put(char.class, lookup.findStatic(Character.class, "hashCode",
|
||||
MethodType.fromMethodDescriptorString("(C)I", loader)));
|
||||
primitiveHashers.put(int.class, lookup.findStatic(Integer.class, "hashCode",
|
||||
MethodType.fromMethodDescriptorString("(I)I", loader)));
|
||||
primitiveHashers.put(long.class, lookup.findStatic(Long.class, "hashCode",
|
||||
MethodType.fromMethodDescriptorString("(J)I", loader)));
|
||||
primitiveHashers.put(float.class, lookup.findStatic(Float.class, "hashCode",
|
||||
MethodType.fromMethodDescriptorString("(F)I", loader)));
|
||||
primitiveHashers.put(double.class, lookup.findStatic(Double.class, "hashCode",
|
||||
MethodType.fromMethodDescriptorString("(D)I", loader)));
|
||||
primitiveHashers.put(boolean.class, lookup.findStatic(Boolean.class, "hashCode",
|
||||
MethodType.fromMethodDescriptorString("(Z)I", loader)));
|
||||
|
||||
primitiveToString.put(byte.class, lookup.findStatic(Byte.class, "toString",
|
||||
MethodType.methodType(String.class, byte.class)));
|
||||
primitiveToString.put(short.class, lookup.findStatic(Short.class, "toString",
|
||||
MethodType.methodType(String.class, short.class)));
|
||||
primitiveToString.put(char.class, lookup.findStatic(Character.class, "toString",
|
||||
MethodType.methodType(String.class, char.class)));
|
||||
primitiveToString.put(int.class, lookup.findStatic(Integer.class, "toString",
|
||||
MethodType.methodType(String.class, int.class)));
|
||||
primitiveToString.put(long.class, lookup.findStatic(Long.class, "toString",
|
||||
MethodType.methodType(String.class, long.class)));
|
||||
primitiveToString.put(float.class, lookup.findStatic(Float.class, "toString",
|
||||
MethodType.methodType(String.class, float.class)));
|
||||
primitiveToString.put(double.class, lookup.findStatic(Double.class, "toString",
|
||||
MethodType.methodType(String.class, double.class)));
|
||||
primitiveToString.put(boolean.class, lookup.findStatic(Boolean.class, "toString",
|
||||
MethodType.methodType(String.class, boolean.class)));
|
||||
}
|
||||
catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static int hashCombiner(int x, int y) {
|
||||
return x*31 + y;
|
||||
}
|
||||
|
||||
private static boolean eq(Object a, Object b) { return a == b; }
|
||||
private static boolean eq(byte a, byte b) { return a == b; }
|
||||
private static boolean eq(short a, short b) { return a == b; }
|
||||
private static boolean eq(char a, char b) { return a == b; }
|
||||
private static boolean eq(int a, int b) { return a == b; }
|
||||
private static boolean eq(long a, long b) { return a == b; }
|
||||
private static boolean eq(float a, float b) { return Float.compare(a, b) == 0; }
|
||||
private static boolean eq(double a, double b) { return Double.compare(a, b) == 0; }
|
||||
private static boolean eq(boolean a, boolean b) { return a == b; }
|
||||
|
||||
/** Get the method handle for combining two values of a given type */
|
||||
private static MethodHandle equalator(Class<?> clazz) {
|
||||
return (clazz.isPrimitive()
|
||||
? primitiveEquals.get(clazz)
|
||||
: OBJECTS_EQUALS.asType(MethodType.methodType(boolean.class, clazz, clazz)));
|
||||
}
|
||||
|
||||
/** Get the hasher for a value of a given type */
|
||||
private static MethodHandle hasher(Class<?> clazz) {
|
||||
return (clazz.isPrimitive()
|
||||
? primitiveHashers.get(clazz)
|
||||
: OBJECTS_HASHCODE.asType(MethodType.methodType(int.class, clazz)));
|
||||
}
|
||||
|
||||
/** Get the stringifier for a value of a given type */
|
||||
private static MethodHandle stringifier(Class<?> clazz) {
|
||||
return (clazz.isPrimitive()
|
||||
? primitiveToString.get(clazz)
|
||||
: OBJECTS_TOSTRING.asType(MethodType.methodType(String.class, clazz)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a method handle for the {@code equals} method for a given data class
|
||||
* @param receiverClass the data class
|
||||
* @param getters the list of getters
|
||||
* @return the method handle
|
||||
*/
|
||||
private static MethodHandle makeEquals(Class<?> receiverClass,
|
||||
List<MethodHandle> getters) {
|
||||
MethodType rr = MethodType.methodType(boolean.class, receiverClass, receiverClass);
|
||||
MethodType ro = MethodType.methodType(boolean.class, receiverClass, Object.class);
|
||||
MethodHandle instanceFalse = MethodHandles.dropArguments(FALSE, 0, receiverClass, Object.class); // (RO)Z
|
||||
MethodHandle instanceTrue = MethodHandles.dropArguments(TRUE, 0, receiverClass, Object.class); // (RO)Z
|
||||
MethodHandle isSameObject = OBJECT_EQ.asType(ro); // (RO)Z
|
||||
MethodHandle isInstance = MethodHandles.dropArguments(CLASS_IS_INSTANCE.bindTo(receiverClass), 0, receiverClass); // (RO)Z
|
||||
MethodHandle accumulator = MethodHandles.dropArguments(TRUE, 0, receiverClass, receiverClass); // (RR)Z
|
||||
|
||||
for (MethodHandle getter : getters) {
|
||||
MethodHandle equalator = equalator(getter.type().returnType()); // (TT)Z
|
||||
MethodHandle thisFieldEqual = MethodHandles.filterArguments(equalator, 0, getter, getter); // (RR)Z
|
||||
accumulator = MethodHandles.guardWithTest(thisFieldEqual, accumulator, instanceFalse.asType(rr));
|
||||
}
|
||||
|
||||
return MethodHandles.guardWithTest(isSameObject,
|
||||
instanceTrue,
|
||||
MethodHandles.guardWithTest(isInstance, accumulator.asType(ro), instanceFalse));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a method handle for the {@code hashCode} method for a given data class
|
||||
* @param receiverClass the data class
|
||||
* @param getters the list of getters
|
||||
* @return the method handle
|
||||
*/
|
||||
private static MethodHandle makeHashCode(Class<?> receiverClass,
|
||||
List<MethodHandle> getters) {
|
||||
MethodHandle accumulator = MethodHandles.dropArguments(ZERO, 0, receiverClass); // (R)I
|
||||
|
||||
// @@@ Use loop combinator instead?
|
||||
for (MethodHandle getter : getters) {
|
||||
MethodHandle hasher = hasher(getter.type().returnType()); // (T)I
|
||||
MethodHandle hashThisField = MethodHandles.filterArguments(hasher, 0, getter); // (R)I
|
||||
MethodHandle combineHashes = MethodHandles.filterArguments(HASH_COMBINER, 0, accumulator, hashThisField); // (RR)I
|
||||
accumulator = MethodHandles.permuteArguments(combineHashes, accumulator.type(), 0, 0); // adapt (R)I to (RR)I
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a method handle for the {@code toString} method for a given data class
|
||||
* @param receiverClass the data class
|
||||
* @param getters the list of getters
|
||||
* @param names the names
|
||||
* @return the method handle
|
||||
*/
|
||||
private static MethodHandle makeToString(Class<?> receiverClass,
|
||||
List<MethodHandle> getters,
|
||||
List<String> names) {
|
||||
// This is a pretty lousy algorithm; we spread the receiver over N places,
|
||||
// apply the N getters, apply N toString operations, and concat the result with String.format
|
||||
// Better to use String.format directly, or delegate to StringConcatFactory
|
||||
// Also probably want some quoting around String components
|
||||
|
||||
assert getters.size() == names.size();
|
||||
|
||||
int[] invArgs = new int[getters.size()];
|
||||
Arrays.fill(invArgs, 0);
|
||||
MethodHandle[] filters = new MethodHandle[getters.size()];
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(receiverClass.getSimpleName()).append("[");
|
||||
for (int i=0; i<getters.size(); i++) {
|
||||
MethodHandle getter = getters.get(i); // (R)T
|
||||
MethodHandle stringify = stringifier(getter.type().returnType()); // (T)String
|
||||
MethodHandle stringifyThisField = MethodHandles.filterArguments(stringify, 0, getter); // (R)String
|
||||
filters[i] = stringifyThisField;
|
||||
sb.append(names.get(i)).append("=%s");
|
||||
if (i != getters.size() - 1)
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(']');
|
||||
String formatString = sb.toString();
|
||||
MethodHandle formatter = MethodHandles.insertArguments(STRING_FORMAT, 0, formatString)
|
||||
.asCollector(String[].class, getters.size()); // (R*)String
|
||||
if (getters.size() == 0) {
|
||||
// Add back extra R
|
||||
formatter = MethodHandles.dropArguments(formatter, 0, receiverClass);
|
||||
}
|
||||
else {
|
||||
MethodHandle filtered = MethodHandles.filterArguments(formatter, 0, filters);
|
||||
formatter = MethodHandles.permuteArguments(filtered, MethodType.methodType(String.class, receiverClass), invArgs);
|
||||
}
|
||||
|
||||
return formatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap method to generate the {@link Object#equals(Object)},
|
||||
* {@link Object#hashCode()}, and {@link Object#toString()} methods, based
|
||||
* on a description of the component names and accessor methods, for either
|
||||
* {@code invokedynamic} call sites or dynamic constant pool entries.
|
||||
*
|
||||
* For more detail on the semantics of the generated methods see the specification
|
||||
* of {@link java.lang.Record#equals(Object)}, {@link java.lang.Record#hashCode()} and
|
||||
* {@link java.lang.Record#toString()}.
|
||||
*
|
||||
*
|
||||
* @param lookup Every bootstrap method is expected to have a {@code lookup}
|
||||
* which usually represents a lookup context with the
|
||||
* accessibility privileges of the caller. This is because
|
||||
* {@code invokedynamic} call sites always provide a {@code lookup}
|
||||
* to the corresponding bootstrap method, but this method just
|
||||
* ignores the {@code lookup} parameter
|
||||
* @param methodName the name of the method to generate, which must be one of
|
||||
* {@code "equals"}, {@code "hashCode"}, or {@code "toString"}
|
||||
* @param type a {@link MethodType} corresponding the descriptor type
|
||||
* for the method, which must correspond to the descriptor
|
||||
* for the corresponding {@link Object} method, if linking
|
||||
* an {@code invokedynamic} call site, or the
|
||||
* constant {@code MethodHandle.class}, if linking a
|
||||
* dynamic constant
|
||||
* @param recordClass the record class hosting the record components
|
||||
* @param names the list of component names, joined into a string
|
||||
* separated by ";", or the empty string if there are no
|
||||
* components. Maybe be null, if the {@code methodName}
|
||||
* is {@code "equals"} or {@code "hashCode"}.
|
||||
* @param getters method handles for the accessor methods for the components
|
||||
* @return a call site if invoked by indy, or a method handle
|
||||
* if invoked by a condy
|
||||
* @throws IllegalArgumentException if the bootstrap arguments are invalid
|
||||
* or inconsistent
|
||||
* @throws Throwable if any exception is thrown during call site construction
|
||||
*/
|
||||
public static Object bootstrap(MethodHandles.Lookup lookup, String methodName, TypeDescriptor type,
|
||||
Class<?> recordClass,
|
||||
String names,
|
||||
MethodHandle... getters) throws Throwable {
|
||||
MethodType methodType;
|
||||
if (type instanceof MethodType)
|
||||
methodType = (MethodType) type;
|
||||
else {
|
||||
methodType = null;
|
||||
if (!MethodHandle.class.equals(type))
|
||||
throw new IllegalArgumentException(type.toString());
|
||||
}
|
||||
List<MethodHandle> getterList = List.of(getters);
|
||||
MethodHandle handle;
|
||||
switch (methodName) {
|
||||
case "equals":
|
||||
if (methodType != null && !methodType.equals(MethodType.methodType(boolean.class, recordClass, Object.class)))
|
||||
throw new IllegalArgumentException("Bad method type: " + methodType);
|
||||
handle = makeEquals(recordClass, getterList);
|
||||
return methodType != null ? new ConstantCallSite(handle) : handle;
|
||||
case "hashCode":
|
||||
if (methodType != null && !methodType.equals(MethodType.methodType(int.class, recordClass)))
|
||||
throw new IllegalArgumentException("Bad method type: " + methodType);
|
||||
handle = makeHashCode(recordClass, getterList);
|
||||
return methodType != null ? new ConstantCallSite(handle) : handle;
|
||||
case "toString":
|
||||
if (methodType != null && !methodType.equals(MethodType.methodType(String.class, recordClass)))
|
||||
throw new IllegalArgumentException("Bad method type: " + methodType);
|
||||
List<String> nameList = "".equals(names) ? List.of() : List.of(names.split(";"));
|
||||
if (nameList.size() != getterList.size())
|
||||
throw new IllegalArgumentException("Name list and accessor list do not match");
|
||||
handle = makeToString(recordClass, getterList, nameList);
|
||||
return methodType != null ? new ConstantCallSite(handle) : handle;
|
||||
default:
|
||||
throw new IllegalArgumentException(methodName);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The {@code java.lang.runtime} package provides low-level runtime support
|
||||
* for the Java language.
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
|
||||
package java.lang.runtime;
|
@ -56,6 +56,7 @@ public @interface PreviewFeature {
|
||||
public enum Feature {
|
||||
PATTERN_MATCHING_IN_INSTANCEOF,
|
||||
TEXT_BLOCKS,
|
||||
RECORDS,
|
||||
;
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ module java.base {
|
||||
exports java.lang.module;
|
||||
exports java.lang.ref;
|
||||
exports java.lang.reflect;
|
||||
exports java.lang.runtime;
|
||||
exports java.math;
|
||||
exports java.net;
|
||||
exports java.net.spi;
|
||||
@ -132,9 +133,12 @@ module java.base {
|
||||
// additional qualified exports may be inserted at build time
|
||||
// see make/gensrc/GenModuleInfo.gmk
|
||||
|
||||
exports sun.invoke.util to
|
||||
jdk.compiler;
|
||||
exports com.sun.security.ntlm to
|
||||
java.security.sasl;
|
||||
exports jdk.internal to
|
||||
java.compiler,
|
||||
jdk.jfr,
|
||||
jdk.compiler;
|
||||
exports jdk.internal.access to
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2019, 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
|
||||
@ -90,7 +90,19 @@ public final class TypeAnnotation {
|
||||
METHOD_RETURN,
|
||||
METHOD_RECEIVER,
|
||||
METHOD_FORMAL_PARAMETER,
|
||||
THROWS;
|
||||
THROWS,
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This enum constant is associated with <i>records</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.}
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
RECORD_COMPONENT;
|
||||
}
|
||||
|
||||
public static final class TypeAnnotationTargetInfo {
|
||||
|
@ -38,6 +38,10 @@
|
||||
#include "check_classname.h"
|
||||
#include "java_lang_Class.h"
|
||||
|
||||
/* defined in libverify.so/verify.dll (src file common/check_format.c) */
|
||||
extern jboolean VerifyClassname(char *utf_name, jboolean arrayAllowed);
|
||||
extern jboolean VerifyFixClassname(char *utf_name);
|
||||
|
||||
#define OBJ "Ljava/lang/Object;"
|
||||
#define CLS "Ljava/lang/Class;"
|
||||
#define CPL "Ljdk/internal/reflect/ConstantPool;"
|
||||
@ -73,6 +77,8 @@ static JNINativeMethod methods[] = {
|
||||
{"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations},
|
||||
{"getNestHost0", "()" CLS, (void *)&JVM_GetNestHost},
|
||||
{"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers},
|
||||
{"getRecordComponents0", "()[" OBJ, (void *)&JVM_GetRecordComponents},
|
||||
{"isRecord0", "()Z", (void *)&JVM_IsRecord},
|
||||
};
|
||||
|
||||
#undef OBJ
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -78,8 +78,8 @@ public interface RoundEnvironment {
|
||||
* The annotation may appear directly or be inherited. Only
|
||||
* package elements, module elements, and type elements <i>included</i> in this
|
||||
* round of annotation processing, or declarations of members,
|
||||
* constructors, parameters, or type parameters declared within
|
||||
* those, are returned. Included type elements are {@linkplain
|
||||
* constructors, parameters, type parameters, or record components
|
||||
* declared within those, are returned. Included type elements are {@linkplain
|
||||
* #getRootElements root types} and any member types nested within
|
||||
* them. Elements of a package are not considered included simply
|
||||
* because a {@code package-info} file for that package was
|
||||
@ -133,8 +133,8 @@ public interface RoundEnvironment {
|
||||
* The annotation may appear directly or be inherited. Only
|
||||
* package elements, module elements, and type elements <i>included</i> in this
|
||||
* round of annotation processing, or declarations of members,
|
||||
* constructors, parameters, or type parameters declared within
|
||||
* those, are returned. Included type elements are {@linkplain
|
||||
* constructors, parameters, type parameters, or record components
|
||||
* declared within those, are returned. Included type elements are {@linkplain
|
||||
* #getRootElements root types} and any member types nested within
|
||||
* them. Elements in a package are not considered included simply
|
||||
* because a {@code package-info} file for that package was
|
||||
|
@ -118,6 +118,7 @@ public interface Element extends javax.lang.model.AnnotatedConstruct {
|
||||
* @see TypeElement#getSimpleName
|
||||
* @see VariableElement#getSimpleName
|
||||
* @see ModuleElement#getSimpleName
|
||||
* @see RecordComponentElement#getSimpleName
|
||||
* @revised 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
@ -148,6 +149,11 @@ public interface Element extends javax.lang.model.AnnotatedConstruct {
|
||||
* parameter}, {@linkplain ExecutableElement the executable
|
||||
* element} which declares the parameter is returned.
|
||||
*
|
||||
* <li> If this is a {@linkplain
|
||||
* RecordComponentElement#getEnclosingElement record component},
|
||||
* {@linkplain TypeElement the type} which declares the
|
||||
* record component is returned.
|
||||
*
|
||||
* <li> If this is a {@linkplain ModuleElement#getEnclosingElement
|
||||
* module}, {@code null} is returned.
|
||||
*
|
||||
@ -166,7 +172,7 @@ public interface Element extends javax.lang.model.AnnotatedConstruct {
|
||||
*
|
||||
* A {@linkplain TypeElement#getEnclosedElements class or
|
||||
* interface} is considered to enclose the fields, methods,
|
||||
* constructors, and member types that it directly declares.
|
||||
* constructors, record components, and member types that it directly declares.
|
||||
*
|
||||
* A {@linkplain PackageElement#getEnclosedElements package}
|
||||
* encloses the top-level classes and interfaces within it, but is
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -46,8 +46,12 @@ public enum ElementKind {
|
||||
// Declared types
|
||||
/** An enum type. */
|
||||
ENUM,
|
||||
/** A class not described by a more specific kind (like {@code ENUM}). */
|
||||
/**
|
||||
* A class not described by a more specific kind (like {@code
|
||||
* ENUM} or {@code RECORD}).
|
||||
*/
|
||||
CLASS,
|
||||
|
||||
/** An annotation type. */
|
||||
ANNOTATION_TYPE,
|
||||
/**
|
||||
@ -90,6 +94,8 @@ public enum ElementKind {
|
||||
*/
|
||||
OTHER,
|
||||
|
||||
// Constants added since initial release
|
||||
|
||||
/**
|
||||
* A resource variable.
|
||||
* @since 1.7
|
||||
@ -101,17 +107,47 @@ public enum ElementKind {
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
MODULE;
|
||||
MODULE,
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This enum constant is associated with <i>records</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.}
|
||||
*
|
||||
* A record type.
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
RECORD,
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This enum constant is associated with <i>records</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.}
|
||||
*
|
||||
* A record component of a {@code record}.
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
RECORD_COMPONENT;
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a kind of class:
|
||||
* either {@code CLASS} or {@code ENUM}.
|
||||
* either {@code CLASS} or {@code ENUM} or {@code RECORD}.
|
||||
*
|
||||
* @return {@code true} if this is a kind of class
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
public boolean isClass() {
|
||||
return this == CLASS || this == ENUM;
|
||||
return this == CLASS || this == ENUM || this == RECORD;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -164,4 +164,29 @@ public interface ElementVisitor<R, P> {
|
||||
default R visitModule(ModuleElement e, P p) {
|
||||
return visitUnknown(e, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>records</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.}
|
||||
*
|
||||
* Visits a record component element.
|
||||
*
|
||||
* @implSpec The default implementation visits a {@code
|
||||
* RecordComponentElement} by calling {@code visitUnknown(e, p)}.
|
||||
*
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return a visitor-specified result
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SuppressWarnings("preview")
|
||||
default R visitRecordComponent(RecordComponentElement e, P p) {
|
||||
return visitUnknown(e, p);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.element;
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This class is associated with <i>records</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.}
|
||||
*
|
||||
* Represents a record component.
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
public interface RecordComponentElement extends Element {
|
||||
/**
|
||||
* Returns the enclosing element of this record component.
|
||||
*
|
||||
* The enclosing element of a record component is the type
|
||||
* declaring the record component.
|
||||
*
|
||||
* @return the enclosing element of this record component
|
||||
*/
|
||||
@Override
|
||||
Element getEnclosingElement();
|
||||
|
||||
/**
|
||||
* Returns the simple name of this record component.
|
||||
*
|
||||
* <p>The name of each record component must be distinct from the
|
||||
* names of all other record components.
|
||||
*
|
||||
* @return the simple name of this record component
|
||||
*
|
||||
* @jls 6.2 Names and Identifiers
|
||||
*/
|
||||
@Override
|
||||
Name getSimpleName();
|
||||
|
||||
/**
|
||||
* Returns the executable element for the accessor associated with the
|
||||
* given record component.
|
||||
*
|
||||
* @return the record component accessor.
|
||||
*/
|
||||
ExecutableElement getAccessor();
|
||||
}
|
@ -32,7 +32,7 @@ import javax.lang.model.util.*;
|
||||
/**
|
||||
* Represents a class or interface program element. Provides access
|
||||
* to information about the type and its members. Note that an enum
|
||||
* type is a kind of class and an annotation type is a kind of
|
||||
* type and a record type are kinds of classes and an annotation type is a kind of
|
||||
* interface.
|
||||
*
|
||||
* <p> While a {@code TypeElement} represents a class or interface
|
||||
@ -82,8 +82,9 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
|
||||
TypeMirror asType();
|
||||
|
||||
/**
|
||||
* Returns the fields, methods, constructors, and member types
|
||||
* that are directly declared in this class or interface.
|
||||
* Returns the fields, methods, constructors, record components,
|
||||
* and member types that are directly declared in this class or
|
||||
* interface.
|
||||
*
|
||||
* This includes any {@linkplain Elements.Origin#MANDATED
|
||||
* mandated} elements such as the (implicit) default constructor
|
||||
@ -177,6 +178,32 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
|
||||
*/
|
||||
List<? extends TypeParameterElement> getTypeParameters();
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>records</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 record components of this type element in
|
||||
* declaration order.
|
||||
*
|
||||
* @implSpec The default implementations of this method returns an
|
||||
* empty and unmodifiable list.
|
||||
*
|
||||
* @return the record components, or an empty list if there are
|
||||
* none
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SuppressWarnings("preview")
|
||||
default List<? extends RecordComponentElement> getRecordComponents() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the package of a top-level type and returns the
|
||||
* immediately lexically enclosing element for a {@linkplain
|
||||
|
@ -90,8 +90,8 @@
|
||||
* new RuntimeException();"}. If a program refers to a missing type Xyz,
|
||||
* the returned model must contain no less information than if the
|
||||
* declaration of type Xyz were assumed to be {@code "class Xyz {}"},
|
||||
* {@code "interface Xyz {}"}, {@code "enum Xyz {}"}, or {@code
|
||||
* "@interface Xyz {}"}. If a program refers to a missing type {@code
|
||||
* {@code "interface Xyz {}"}, {@code "enum Xyz {}"}, {@code
|
||||
* "@interface Xyz {}"}, or {@code "record Xyz {}"}. If a program refers to a missing type {@code
|
||||
* Xyz<K1, ... ,Kn>}, the returned model must contain no less
|
||||
* information than if the declaration of Xyz were assumed to be
|
||||
* {@code "class Xyz<T1, ... ,Tn> {}"} or {@code "interface Xyz<T1,
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.util;
|
||||
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
|
||||
/**
|
||||
* A skeletal visitor for annotation values with default behavior
|
||||
* appropriate for source version {@link SourceVersion#RELEASE_14 RELEASE_14}.
|
||||
*
|
||||
* <p> <b>WARNING:</b> The {@code AnnotationValueVisitor} interface
|
||||
* implemented by this class may have methods added to it in the
|
||||
* future to accommodate new, currently unknown, language structures
|
||||
* added to future versions of the Java™ programming language.
|
||||
* Therefore, methods whose names begin with {@code "visit"} may be
|
||||
* added to this class in the future; to avoid incompatibilities,
|
||||
* classes which extend this class should not declare any instance
|
||||
* methods with names beginning with {@code "visit"}.
|
||||
*
|
||||
* <p>When such a new visit method is added, the default
|
||||
* implementation in this class will be to call the {@link
|
||||
* #visitUnknown visitUnknown} method. A new abstract annotation
|
||||
* value visitor class will also be introduced to correspond to the
|
||||
* new language level; this visitor will have different default
|
||||
* behavior for the visit method in question. When the new visitor is
|
||||
* introduced, all or portions of this visitor may be deprecated.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods
|
||||
* @param <P> the type of the additional parameter to this visitor's methods.
|
||||
*
|
||||
* @see AbstractAnnotationValueVisitor6
|
||||
* @see AbstractAnnotationValueVisitor7
|
||||
* @see AbstractAnnotationValueVisitor8
|
||||
* @see AbstractAnnotationValueVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
public abstract class AbstractAnnotationValueVisitor14<R, P> extends AbstractAnnotationValueVisitor9<R, P> {
|
||||
|
||||
/**
|
||||
* Constructor for concrete subclasses to call.
|
||||
*/
|
||||
protected AbstractAnnotationValueVisitor14() {
|
||||
super();
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -64,6 +64,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
||||
* @see AbstractAnnotationValueVisitor7
|
||||
* @see AbstractAnnotationValueVisitor8
|
||||
* @see AbstractAnnotationValueVisitor9
|
||||
* @see AbstractAnnotationValueVisitor14
|
||||
* @since 1.6
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_6)
|
||||
|
@ -57,6 +57,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
||||
* @see AbstractAnnotationValueVisitor6
|
||||
* @see AbstractAnnotationValueVisitor8
|
||||
* @see AbstractAnnotationValueVisitor9
|
||||
* @see AbstractAnnotationValueVisitor14
|
||||
* @since 1.7
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_7)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, 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
|
||||
@ -57,6 +57,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
||||
* @see AbstractAnnotationValueVisitor6
|
||||
* @see AbstractAnnotationValueVisitor7
|
||||
* @see AbstractAnnotationValueVisitor9
|
||||
* @see AbstractAnnotationValueVisitor14
|
||||
* @since 1.8
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_8)
|
||||
|
@ -57,6 +57,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
||||
* @see AbstractAnnotationValueVisitor6
|
||||
* @see AbstractAnnotationValueVisitor7
|
||||
* @see AbstractAnnotationValueVisitor8
|
||||
* @see AbstractAnnotationValueVisitor14
|
||||
* @since 9
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.util;
|
||||
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.RecordComponentElement;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This class is associated with <i>records</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.}
|
||||
*
|
||||
* A skeletal visitor of program elements with default behavior
|
||||
* appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14}
|
||||
* source version.
|
||||
*
|
||||
* <p> <b>WARNING:</b> The {@code ElementVisitor} interface
|
||||
* implemented by this class may have methods added to it in the
|
||||
* future to accommodate new, currently unknown, language structures
|
||||
* added to future versions of the Java™ programming language.
|
||||
* Therefore, methods whose names begin with {@code "visit"} may be
|
||||
* added to this class in the future; to avoid incompatibilities,
|
||||
* classes which extend this class should not declare any instance
|
||||
* methods with names beginning with {@code "visit"}.
|
||||
*
|
||||
* <p>When such a new visit method is added, the default
|
||||
* implementation in this class will be to call the {@link
|
||||
* #visitUnknown visitUnknown} method. A new abstract element visitor
|
||||
* class will also be introduced to correspond to the new language
|
||||
* level; this visitor will have different default behavior for the
|
||||
* visit method in question. When the new visitor is introduced, all
|
||||
* or portions of this visitor may be deprecated.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods. Use {@link
|
||||
* Void} for visitors that do not need to return results.
|
||||
* @param <P> the type of the additional parameter to this visitor's
|
||||
* methods. Use {@code Void} for visitors that do not need an
|
||||
* additional parameter.
|
||||
*
|
||||
* @see AbstractElementVisitor6
|
||||
* @see AbstractElementVisitor7
|
||||
* @see AbstractElementVisitor8
|
||||
* @see AbstractElementVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
public abstract class AbstractElementVisitor14<R, P> extends AbstractElementVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses to call.
|
||||
*/
|
||||
protected AbstractElementVisitor14(){
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec Visits a {@code RecordComponentElement} in a manner defined by a
|
||||
* subclass.
|
||||
*
|
||||
* @param t {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
* @return {@inheritDoc}
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
@Override
|
||||
public abstract R visitRecordComponent(RecordComponentElement t, P p);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -66,6 +66,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractElementVisitor7
|
||||
* @see AbstractElementVisitor8
|
||||
* @see AbstractElementVisitor9
|
||||
* @see AbstractElementVisitor14
|
||||
* @since 1.6
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_6)
|
||||
@ -143,4 +144,23 @@ public abstract class AbstractElementVisitor6<R, P> implements ElementVisitor<R,
|
||||
// Use implementation from interface default method
|
||||
return ElementVisitor.super.visitModule(e, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec Visits a {@code RecordComponentElement} by calling {@code
|
||||
* visitUnknown}.
|
||||
*
|
||||
* @param e {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
* @return {@inheritDoc}
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
@Override
|
||||
public R visitRecordComponent(RecordComponentElement e, P p) {
|
||||
// Use implementation from interface default method
|
||||
return ElementVisitor.super.visitRecordComponent(e, p);
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractElementVisitor6
|
||||
* @see AbstractElementVisitor8
|
||||
* @see AbstractElementVisitor9
|
||||
* @see AbstractElementVisitor14
|
||||
* @since 1.7
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_7)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, 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
|
||||
@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractElementVisitor6
|
||||
* @see AbstractElementVisitor7
|
||||
* @see AbstractElementVisitor9
|
||||
* @see AbstractElementVisitor14
|
||||
* @since 1.8
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_8)
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.util;
|
||||
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
|
||||
/**
|
||||
* A skeletal visitor of types with default behavior appropriate for the
|
||||
* {@link SourceVersion#RELEASE_14 RELEASE_14} source version.
|
||||
*
|
||||
* <p> <b>WARNING:</b> The {@code TypeVisitor} interface implemented
|
||||
* by this class may have methods added to it in the future to
|
||||
* accommodate new, currently unknown, language structures added to
|
||||
* future versions of the Java™ programming language.
|
||||
* Therefore, methods whose names begin with {@code "visit"} may be
|
||||
* added to this class in the future; to avoid incompatibilities,
|
||||
* classes which extend this class should not declare any instance
|
||||
* methods with names beginning with {@code "visit"}.
|
||||
*
|
||||
* <p>When such a new visit method is added, the default
|
||||
* implementation in this class will be to call the {@link
|
||||
* #visitUnknown visitUnknown} method. A new abstract type visitor
|
||||
* class will also be introduced to correspond to the new language
|
||||
* level; this visitor will have different default behavior for the
|
||||
* visit method in question. When the new visitor is introduced, all
|
||||
* or portions of this visitor may be deprecated.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods. Use {@link
|
||||
* Void} for visitors that do not need to return results.
|
||||
* @param <P> the type of the additional parameter to this visitor's
|
||||
* methods. Use {@code Void} for visitors that do not need an
|
||||
* additional parameter.
|
||||
*
|
||||
* @see AbstractTypeVisitor6
|
||||
* @see AbstractTypeVisitor7
|
||||
* @see AbstractTypeVisitor8
|
||||
* @see AbstractTypeVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
public abstract class AbstractTypeVisitor14<R, P> extends AbstractTypeVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses to call.
|
||||
*/
|
||||
protected AbstractTypeVisitor14() {
|
||||
super();
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -65,6 +65,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractTypeVisitor7
|
||||
* @see AbstractTypeVisitor8
|
||||
* @see AbstractTypeVisitor9
|
||||
* @see AbstractTypeVisitor14
|
||||
* @since 1.6
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_6)
|
||||
|
@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractTypeVisitor6
|
||||
* @see AbstractTypeVisitor8
|
||||
* @see AbstractTypeVisitor9
|
||||
* @see AbstractTypeVisitor14
|
||||
* @since 1.7
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_7)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, 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
|
||||
@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractTypeVisitor6
|
||||
* @see AbstractTypeVisitor7
|
||||
* @see AbstractTypeVisitor9
|
||||
* @see AbstractTypeVisitor14
|
||||
* @since 1.8
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_8)
|
||||
|
@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see AbstractTypeVisitor6
|
||||
* @see AbstractTypeVisitor7
|
||||
* @see AbstractTypeVisitor8
|
||||
* @see AbstractTypeVisitor14
|
||||
* @since 9
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -79,11 +79,18 @@ public class ElementFilter {
|
||||
private static final Set<ElementKind> MODULE_KIND =
|
||||
Collections.unmodifiableSet(EnumSet.of(ElementKind.MODULE));
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
private static final Set<ElementKind> TYPE_KINDS =
|
||||
Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS,
|
||||
ElementKind.ENUM,
|
||||
ElementKind.INTERFACE,
|
||||
ElementKind.RECORD,
|
||||
ElementKind.ANNOTATION_TYPE));
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
private static final Set<ElementKind> RECORD_COMPONENT_KIND =
|
||||
Set.of(ElementKind.RECORD_COMPONENT);
|
||||
|
||||
/**
|
||||
* Returns a list of fields in {@code elements}.
|
||||
* @return a list of fields in {@code elements}
|
||||
@ -104,6 +111,48 @@ public class ElementFilter {
|
||||
return setFilter(elements, FIELD_KINDS, VariableElement.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>records</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 a list of record components in {@code elements}.
|
||||
* @return a list of record components in {@code elements}
|
||||
* @param elements the elements to filter
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SuppressWarnings("preview")
|
||||
public static List<RecordComponentElement>
|
||||
recordComponentsIn(Iterable<? extends Element> elements) {
|
||||
return listFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>records</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 a set of record components in {@code elements}.
|
||||
* @return a set of record components in {@code elements}
|
||||
* @param elements the elements to filter
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SuppressWarnings("preview")
|
||||
public static Set<RecordComponentElement>
|
||||
recordComponentsIn(Set<? extends Element> elements) {
|
||||
return setFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of constructors in {@code elements}.
|
||||
* @return a list of constructors in {@code elements}
|
||||
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.util;
|
||||
|
||||
import javax.lang.model.element.*;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
import javax.lang.model.SourceVersion;
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This class is associated with <i>records</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.}
|
||||
*
|
||||
* A visitor of program elements based on their {@linkplain
|
||||
* ElementKind kind} with default behavior appropriate for the {@link
|
||||
* SourceVersion#RELEASE_14 RELEASE_14} source version.
|
||||
*
|
||||
* For {@linkplain
|
||||
* Element elements} <code><i>Xyz</i></code> that may have more than one
|
||||
* kind, the <code>visit<i>Xyz</i></code> methods in this class delegate
|
||||
* to the <code>visit<i>Xyz</i>As<i>Kind</i></code> method corresponding to the
|
||||
* first argument's kind. The <code>visit<i>Xyz</i>As<i>Kind</i></code> methods
|
||||
* call {@link #defaultAction defaultAction}, passing their arguments
|
||||
* to {@code defaultAction}'s corresponding parameters.
|
||||
*
|
||||
* <p> Methods in this class may be overridden subject to their
|
||||
* general contract. Note that annotating methods in concrete
|
||||
* subclasses with {@link java.lang.Override @Override} will help
|
||||
* ensure that methods are overridden as intended.
|
||||
*
|
||||
* <p> <b>WARNING:</b> The {@code ElementVisitor} interface
|
||||
* implemented by this class may have methods added to it or the
|
||||
* {@code ElementKind} {@code enum} used in this case may have
|
||||
* constants added to it in the future to accommodate new, currently
|
||||
* unknown, language structures added to future versions of the
|
||||
* Java™ programming language. Therefore, methods whose names
|
||||
* begin with {@code "visit"} may be added to this class in the
|
||||
* future; to avoid incompatibilities, classes which extend this class
|
||||
* should not declare any instance methods with names beginning with
|
||||
* {@code "visit"}.
|
||||
*
|
||||
* <p>When such a new visit method is added, the default
|
||||
* implementation in this class will be to call the {@link
|
||||
* #visitUnknown visitUnknown} method. A new abstract element kind
|
||||
* visitor class will also be introduced to correspond to the new
|
||||
* language level; this visitor will have different default behavior
|
||||
* for the visit method in question. When the new visitor is
|
||||
* introduced, all or portions of this visitor may be deprecated.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods. Use {@link
|
||||
* Void} for visitors that do not need to return results.
|
||||
* @param <P> the type of the additional parameter to this visitor's
|
||||
* methods. Use {@code Void} for visitors that do not need an
|
||||
* additional parameter.
|
||||
*
|
||||
* @see ElementKindVisitor6
|
||||
* @see ElementKindVisitor7
|
||||
* @see ElementKindVisitor8
|
||||
* @see ElementKindVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
public class ElementKindVisitor14<R, P> extends ElementKindVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
* default value.
|
||||
*/
|
||||
protected ElementKindVisitor14() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses the argument for the
|
||||
* default value.
|
||||
*
|
||||
* @param defaultValue the value to assign to {@link #DEFAULT_VALUE}
|
||||
*/
|
||||
protected ElementKindVisitor14(R defaultValue) {
|
||||
super(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec This implementation calls {@code defaultAction}.
|
||||
*
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of {@code defaultAction}
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
@Override
|
||||
public R visitRecordComponent(RecordComponentElement e, P p) {
|
||||
return defaultAction(e, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec This implementation calls {@code defaultAction}.
|
||||
*.
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of {@code defaultAction}
|
||||
*/
|
||||
@Override
|
||||
public R visitTypeAsRecord(TypeElement e, P p) {
|
||||
return defaultAction(e, p);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -80,6 +80,7 @@ import javax.lang.model.SourceVersion;
|
||||
* @see ElementKindVisitor7
|
||||
* @see ElementKindVisitor8
|
||||
* @see ElementKindVisitor9
|
||||
* @see ElementKindVisitor14
|
||||
* @since 1.6
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_6)
|
||||
@ -138,6 +139,7 @@ public class ElementKindVisitor6<R, P>
|
||||
* @param p {@inheritDoc}
|
||||
* @return the result of the kind-specific visit method
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
@Override
|
||||
public R visitType(TypeElement e, P p) {
|
||||
ElementKind k = e.getKind();
|
||||
@ -154,6 +156,9 @@ public class ElementKindVisitor6<R, P>
|
||||
case INTERFACE:
|
||||
return visitTypeAsInterface(e, p);
|
||||
|
||||
case RECORD:
|
||||
return visitTypeAsRecord(e, p);
|
||||
|
||||
default:
|
||||
throw new AssertionError("Bad kind " + k + " for TypeElement" + e);
|
||||
}
|
||||
@ -211,6 +216,30 @@ public class ElementKindVisitor6<R, P>
|
||||
return defaultAction(e, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>records</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.}
|
||||
*
|
||||
* Visits a {@code RECORD} type element.
|
||||
*
|
||||
* @implSpec This implementation calls {@code visitUnknown}.
|
||||
*.
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of {@code visitUnknown}
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
public R visitTypeAsRecord(TypeElement e, P p) {
|
||||
return visitUnknown(e, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a variable element
|
||||
*
|
||||
|
@ -74,6 +74,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see ElementKindVisitor6
|
||||
* @see ElementKindVisitor8
|
||||
* @see ElementKindVisitor9
|
||||
* @see ElementKindVisitor14
|
||||
* @since 1.7
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_7)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, 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
|
||||
@ -74,6 +74,7 @@ import javax.lang.model.SourceVersion;
|
||||
* @see ElementKindVisitor6
|
||||
* @see ElementKindVisitor7
|
||||
* @see ElementKindVisitor9
|
||||
* @see ElementKindVisitor14
|
||||
* @since 1.8
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_8)
|
||||
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.util;
|
||||
|
||||
import javax.lang.model.element.*;
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This class is associated with <i>records</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.}
|
||||
*
|
||||
* A scanning visitor of program elements with default behavior
|
||||
* appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14}
|
||||
* source version.
|
||||
*
|
||||
* The <code>visit<i>Xyz</i></code> methods in this
|
||||
* class scan their component elements by calling {@code scan} on
|
||||
* their {@linkplain Element#getEnclosedElements enclosed elements},
|
||||
* {@linkplain ExecutableElement#getParameters parameters}, etc., as
|
||||
* indicated in the individual method specifications. A subclass can
|
||||
* control the order elements are visited by overriding the
|
||||
* <code>visit<i>Xyz</i></code> methods. Note that clients of a scanner
|
||||
* may get the desired behavior be invoking {@code v.scan(e, p)} rather
|
||||
* than {@code v.visit(e, p)} on the root objects of interest.
|
||||
*
|
||||
* <p>When a subclass overrides a <code>visit<i>Xyz</i></code> method, the
|
||||
* new method can cause the enclosed elements to be scanned in the
|
||||
* default way by calling <code>super.visit<i>Xyz</i></code>. In this
|
||||
* fashion, the concrete visitor can control the ordering of traversal
|
||||
* over the component elements with respect to the additional
|
||||
* processing; for example, consistently calling
|
||||
* <code>super.visit<i>Xyz</i></code> at the start of the overridden
|
||||
* methods will yield a preorder traversal, etc. If the component
|
||||
* elements should be traversed in some other order, instead of
|
||||
* calling <code>super.visit<i>Xyz</i></code>, an overriding visit method
|
||||
* should call {@code scan} with the elements in the desired order.
|
||||
*
|
||||
* <p> Methods in this class may be overridden subject to their
|
||||
* general contract. Note that annotating methods in concrete
|
||||
* subclasses with {@link java.lang.Override @Override} will help
|
||||
* ensure that methods are overridden as intended.
|
||||
*
|
||||
* <p> <b>WARNING:</b> The {@code ElementVisitor} interface
|
||||
* implemented by this class may have methods added to it in the
|
||||
* future to accommodate new, currently unknown, language structures
|
||||
* added to future versions of the Java™ programming language.
|
||||
* Therefore, methods whose names begin with {@code "visit"} may be
|
||||
* added to this class in the future; to avoid incompatibilities,
|
||||
* classes which extend this class should not declare any instance
|
||||
* methods with names beginning with {@code "visit"}.
|
||||
*
|
||||
* <p>When such a new visit method is added, the default
|
||||
* implementation in this class will be to call the {@link
|
||||
* #visitUnknown visitUnknown} method. A new element scanner visitor
|
||||
* class will also be introduced to correspond to the new language
|
||||
* level; this visitor will have different default behavior for the
|
||||
* visit method in question. When the new visitor is introduced, all
|
||||
* or portions of this visitor may be deprecated.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods. Use {@link
|
||||
* Void} for visitors that do not need to return results.
|
||||
* @param <P> the type of the additional parameter to this visitor's
|
||||
* methods. Use {@code Void} for visitors that do not need an
|
||||
* additional parameter.
|
||||
*
|
||||
* @see ElementScanner6
|
||||
* @see ElementScanner7
|
||||
* @see ElementScanner8
|
||||
* @see ElementScanner9
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
public class ElementScanner14<R, P> extends ElementScanner9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
* default value.
|
||||
*/
|
||||
protected ElementScanner14(){
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses the argument for the
|
||||
* default value.
|
||||
*
|
||||
* @param defaultValue the default value
|
||||
*/
|
||||
protected ElementScanner14(R defaultValue){
|
||||
super(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec This implementation scans the enclosed elements.
|
||||
*
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return the result of the scan
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
@Override
|
||||
public R visitRecordComponent(RecordComponentElement e, P p) {
|
||||
return scan(e.getEnclosedElements(), p);
|
||||
}
|
||||
}
|
@ -91,6 +91,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see ElementScanner7
|
||||
* @see ElementScanner8
|
||||
* @see ElementScanner9
|
||||
* @see ElementScanner14
|
||||
* @since 1.6
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_6)
|
||||
|
@ -87,6 +87,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see ElementScanner6
|
||||
* @see ElementScanner8
|
||||
* @see ElementScanner9
|
||||
* @see ElementScanner14
|
||||
* @since 1.7
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_7)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, 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
|
||||
@ -87,6 +87,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see ElementScanner6
|
||||
* @see ElementScanner7
|
||||
* @see ElementScanner9
|
||||
* @see ElementScanner14
|
||||
* @since 1.8
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_8)
|
||||
|
@ -89,6 +89,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see ElementScanner6
|
||||
* @see ElementScanner7
|
||||
* @see ElementScanner8
|
||||
* @see ElementScanner14
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
@ -31,6 +31,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.lang.model.AnnotatedConstruct;
|
||||
import javax.lang.model.element.*;
|
||||
@ -629,4 +630,42 @@ public interface Elements {
|
||||
* @since 1.8
|
||||
*/
|
||||
boolean isFunctionalInterface(TypeElement type);
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This method is associated with <i>records</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 record component for the given accessor. Returns null if the
|
||||
* given method is not a record component accessor.
|
||||
*
|
||||
* @implSpec The default implementation of this method checks if the element
|
||||
* enclosing the accessor has kind {@link ElementKind#RECORD RECORD} if that is
|
||||
* the case, then all the record components on the accessor's enclosing element
|
||||
* are retrieved by invoking {@link ElementFilter#recordComponentsIn(Iterable)}.
|
||||
* If the accessor of at least one of the record components retrieved happen to
|
||||
* be equal to the accessor passed as a parameter to this method, then that
|
||||
* record component is returned, in any other case {@code null} is returned.
|
||||
*
|
||||
* @param accessor the method for which the record component should be found.
|
||||
* @return the record component, or null if the given method is not an record
|
||||
* component accessor
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SuppressWarnings("preview")
|
||||
default RecordComponentElement recordComponentFor(ExecutableElement accessor) {
|
||||
if (accessor.getEnclosingElement().getKind() == ElementKind.RECORD) {
|
||||
for (RecordComponentElement rec : ElementFilter.recordComponentsIn(accessor.getEnclosingElement().getEnclosedElements())) {
|
||||
if (Objects.equals(rec.getAccessor(), accessor)) {
|
||||
return rec;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.util;
|
||||
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
|
||||
/**
|
||||
* A simple visitor for annotation values with default behavior
|
||||
* appropriate for source version {@link SourceVersion#RELEASE_14 RELEASE_14}.
|
||||
*
|
||||
* Visit methods call {@link #defaultAction
|
||||
* defaultAction} passing their arguments to {@code defaultAction}'s
|
||||
* corresponding parameters.
|
||||
*
|
||||
* <p> Methods in this class may be overridden subject to their
|
||||
* general contract. Note that annotating methods in concrete
|
||||
* subclasses with {@link java.lang.Override @Override} will help
|
||||
* ensure that methods are overridden as intended.
|
||||
*
|
||||
* <p> <b>WARNING:</b> The {@code AnnotationValueVisitor} interface
|
||||
* implemented by this class may have methods added to it in the
|
||||
* future to accommodate new, currently unknown, language structures
|
||||
* added to future versions of the Java™ programming language.
|
||||
* Therefore, methods whose names begin with {@code "visit"} may be
|
||||
* added to this class in the future; to avoid incompatibilities,
|
||||
* classes which extend this class should not declare any instance
|
||||
* methods with names beginning with {@code "visit"}.
|
||||
*
|
||||
* <p>When such a new visit method is added, the default
|
||||
* implementation in this class will be to call the {@link
|
||||
* #visitUnknown visitUnknown} method. A new simple annotation
|
||||
* value visitor class will also be introduced to correspond to the
|
||||
* new language level; this visitor will have different default
|
||||
* behavior for the visit method in question. When the new visitor is
|
||||
* introduced, all or portions of this visitor may be deprecated.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods
|
||||
* @param <P> the type of the additional parameter to this visitor's methods.
|
||||
*
|
||||
* @see SimpleAnnotationValueVisitor6
|
||||
* @see SimpleAnnotationValueVisitor7
|
||||
* @see SimpleAnnotationValueVisitor8
|
||||
* @see SimpleAnnotationValueVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
public class SimpleAnnotationValueVisitor14<R, P> extends SimpleAnnotationValueVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
* default value.
|
||||
*/
|
||||
protected SimpleAnnotationValueVisitor14() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses the argument for the
|
||||
* default value.
|
||||
*
|
||||
* @param defaultValue the value to assign to {@link #DEFAULT_VALUE}
|
||||
*/
|
||||
protected SimpleAnnotationValueVisitor14(R defaultValue) {
|
||||
super(defaultValue);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -73,6 +73,7 @@ import javax.annotation.processing.SupportedSourceVersion;
|
||||
* @see SimpleAnnotationValueVisitor7
|
||||
* @see SimpleAnnotationValueVisitor8
|
||||
* @see SimpleAnnotationValueVisitor9
|
||||
* @see SimpleAnnotationValueVisitor14
|
||||
* @since 1.6
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_6)
|
||||
|
@ -64,6 +64,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleAnnotationValueVisitor6
|
||||
* @see SimpleAnnotationValueVisitor8
|
||||
* @see SimpleAnnotationValueVisitor9
|
||||
* @see SimpleAnnotationValueVisitor14
|
||||
* @since 1.7
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_7)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, 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
|
||||
@ -64,6 +64,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleAnnotationValueVisitor6
|
||||
* @see SimpleAnnotationValueVisitor7
|
||||
* @see SimpleAnnotationValueVisitor8
|
||||
* @see SimpleAnnotationValueVisitor14
|
||||
* @since 1.8
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_8)
|
||||
|
@ -66,6 +66,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleAnnotationValueVisitor6
|
||||
* @see SimpleAnnotationValueVisitor7
|
||||
* @see SimpleAnnotationValueVisitor8
|
||||
* @see SimpleAnnotationValueVisitor14
|
||||
* @since 9
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.util;
|
||||
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.RecordComponentElement;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This class is associated with <i>records</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.}
|
||||
*
|
||||
* A simple visitor of program elements with default behavior
|
||||
* appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14}
|
||||
* source version.
|
||||
*
|
||||
* Visit methods corresponding to {@code RELEASE_14} and earlier
|
||||
* language constructs call {@link #defaultAction defaultAction},
|
||||
* passing their arguments to {@code defaultAction}'s corresponding
|
||||
* parameters.
|
||||
*
|
||||
* <p> Methods in this class may be overridden subject to their
|
||||
* general contract. Note that annotating methods in concrete
|
||||
* subclasses with {@link java.lang.Override @Override} will help
|
||||
* ensure that methods are overridden as intended.
|
||||
*
|
||||
* <p> <b>WARNING:</b> The {@code ElementVisitor} interface
|
||||
* implemented by this class may have methods added to it in the
|
||||
* future to accommodate new, currently unknown, language structures
|
||||
* added to future versions of the Java™ programming language.
|
||||
* Therefore, methods whose names begin with {@code "visit"} may be
|
||||
* added to this class in the future; to avoid incompatibilities,
|
||||
* classes which extend this class should not declare any instance
|
||||
* methods with names beginning with {@code "visit"}.
|
||||
*
|
||||
* <p>When such a new visit method is added, the default
|
||||
* implementation in this class will be to call the {@link
|
||||
* #visitUnknown visitUnknown} method. A new simple element visitor
|
||||
* class will also be introduced to correspond to the new language
|
||||
* level; this visitor will have different default behavior for the
|
||||
* visit method in question. When the new visitor is introduced, all
|
||||
* or portions of this visitor may be deprecated.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods. Use {@code Void}
|
||||
* for visitors that do not need to return results.
|
||||
* @param <P> the type of the additional parameter to this visitor's methods. Use {@code Void}
|
||||
* for visitors that do not need an additional parameter.
|
||||
*
|
||||
* @see SimpleElementVisitor6
|
||||
* @see SimpleElementVisitor7
|
||||
* @see SimpleElementVisitor8
|
||||
* @see SimpleElementVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
public class SimpleElementVisitor14<R, P> extends SimpleElementVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
* default value.
|
||||
*/
|
||||
protected SimpleElementVisitor14(){
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses the argument for the
|
||||
* default value.
|
||||
*
|
||||
* @param defaultValue the value to assign to {@link #DEFAULT_VALUE}
|
||||
*/
|
||||
protected SimpleElementVisitor14(R defaultValue){
|
||||
super(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec Visits a {@code RecordComponentElement} by calling {@code
|
||||
* defaultAction}.
|
||||
*
|
||||
* @param e the element to visit
|
||||
* @param p a visitor-specified parameter
|
||||
* @return {@inheritDoc}
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
@Override
|
||||
public R visitRecordComponent(RecordComponentElement e, P p) {
|
||||
return defaultAction(e, p);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -77,6 +77,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleElementVisitor7
|
||||
* @see SimpleElementVisitor8
|
||||
* @see SimpleElementVisitor9
|
||||
* @see SimpleElementVisitor14
|
||||
* @since 1.6
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_6)
|
||||
|
@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleElementVisitor6
|
||||
* @see SimpleElementVisitor8
|
||||
* @see SimpleElementVisitor9
|
||||
* @see SimpleElementVisitor14
|
||||
* @since 1.7
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_7)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, 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
|
||||
@ -69,6 +69,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleElementVisitor6
|
||||
* @see SimpleElementVisitor7
|
||||
* @see SimpleElementVisitor9
|
||||
* @see SimpleElementVisitor14
|
||||
* @since 1.8
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_8)
|
||||
|
@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleElementVisitor6
|
||||
* @see SimpleElementVisitor7
|
||||
* @see SimpleElementVisitor8
|
||||
* @see SimpleElementVisitor14
|
||||
* @since 9
|
||||
* @spec JPMS
|
||||
*/
|
||||
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.util;
|
||||
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
|
||||
/**
|
||||
* A simple visitor of types with default behavior appropriate for
|
||||
* source version {@link SourceVersion#RELEASE_14 RELEASE_14}.
|
||||
*
|
||||
* Visit methods corresponding to {@code RELEASE_14} and earlier
|
||||
* language constructs call {@link #defaultAction defaultAction},
|
||||
* passing their arguments to {@code defaultAction}'s corresponding
|
||||
* parameters.
|
||||
*
|
||||
* <p> Methods in this class may be overridden subject to their
|
||||
* general contract. Note that annotating methods in concrete
|
||||
* subclasses with {@link java.lang.Override @Override} will help
|
||||
* ensure that methods are overridden as intended.
|
||||
*
|
||||
* <p> <b>WARNING:</b> The {@code TypeVisitor} interface implemented
|
||||
* by this class may have methods added to it in the future to
|
||||
* accommodate new, currently unknown, language structures added to
|
||||
* future versions of the Java™ programming language.
|
||||
* Therefore, methods whose names begin with {@code "visit"} may be
|
||||
* added to this class in the future; to avoid incompatibilities,
|
||||
* classes which extend this class should not declare any instance
|
||||
* methods with names beginning with {@code "visit"}.
|
||||
*
|
||||
* <p>When such a new visit method is added, the default
|
||||
* implementation in this class will be to call the {@link
|
||||
* #visitUnknown visitUnknown} method. A new simple type visitor
|
||||
* class will also be introduced to correspond to the new language
|
||||
* level; this visitor will have different default behavior for the
|
||||
* visit method in question. When the new visitor is introduced, all
|
||||
* or portions of this visitor may be deprecated.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods. Use {@link
|
||||
* Void} for visitors that do not need to return results.
|
||||
* @param <P> the type of the additional parameter to this visitor's
|
||||
* methods. Use {@code Void} for visitors that do not need an
|
||||
* additional parameter.
|
||||
*
|
||||
* @see SimpleTypeVisitor6
|
||||
* @see SimpleTypeVisitor7
|
||||
* @see SimpleTypeVisitor8
|
||||
* @see SimpleTypeVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
public class SimpleTypeVisitor14<R, P> extends SimpleTypeVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses {@code null} for the
|
||||
* default value.
|
||||
*/
|
||||
protected SimpleTypeVisitor14(){
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for concrete subclasses; uses the argument for the
|
||||
* default value.
|
||||
*
|
||||
* @param defaultValue the value to assign to {@link #DEFAULT_VALUE}
|
||||
*/
|
||||
protected SimpleTypeVisitor14(R defaultValue){
|
||||
super(defaultValue);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -77,6 +77,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleTypeVisitor7
|
||||
* @see SimpleTypeVisitor8
|
||||
* @see SimpleTypeVisitor9
|
||||
* @see SimpleTypeVisitor14
|
||||
* @since 1.6
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_6)
|
||||
|
@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleTypeVisitor6
|
||||
* @see SimpleTypeVisitor8
|
||||
* @see SimpleTypeVisitor9
|
||||
* @see SimpleTypeVisitor14
|
||||
* @since 1.7
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_7)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, 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
|
||||
@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleTypeVisitor6
|
||||
* @see SimpleTypeVisitor7
|
||||
* @see SimpleTypeVisitor9
|
||||
* @see SimpleTypeVisitor14
|
||||
* @since 1.8
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_8)
|
||||
|
@ -71,6 +71,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see SimpleTypeVisitor6
|
||||
* @see SimpleTypeVisitor7
|
||||
* @see SimpleTypeVisitor8
|
||||
* @see SimpleTypeVisitor14
|
||||
* @since 9
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 javax.lang.model.util;
|
||||
|
||||
import javax.annotation.processing.SupportedSourceVersion;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.type.*;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
|
||||
/**
|
||||
* A visitor of types based on their {@linkplain TypeKind kind} with
|
||||
* default behavior appropriate for source version {@link
|
||||
* SourceVersion#RELEASE_14 RELEASE_14}.
|
||||
*
|
||||
* For {@linkplain
|
||||
* TypeMirror types} <code><i>Xyz</i></code> that may have more than one
|
||||
* kind, the <code>visit<i>Xyz</i></code> methods in this class delegate
|
||||
* to the <code>visit<i>Xyz</i>As<i>Kind</i></code> method corresponding to the
|
||||
* first argument's kind. The <code>visit<i>Xyz</i>As<i>Kind</i></code> methods
|
||||
* call {@link #defaultAction defaultAction}, passing their arguments
|
||||
* to {@code defaultAction}'s corresponding parameters.
|
||||
*
|
||||
* <p> Methods in this class may be overridden subject to their
|
||||
* general contract. Note that annotating methods in concrete
|
||||
* subclasses with {@link java.lang.Override @Override} will help
|
||||
* ensure that methods are overridden as intended.
|
||||
*
|
||||
* <p> <b>WARNING:</b> The {@code TypeVisitor} interface implemented
|
||||
* by this class may have methods added to it in the future to
|
||||
* accommodate new, currently unknown, language structures added to
|
||||
* future versions of the Java™ programming language.
|
||||
* Therefore, methods whose names begin with {@code "visit"} may be
|
||||
* added to this class in the future; to avoid incompatibilities,
|
||||
* classes which extend this class should not declare any instance
|
||||
* methods with names beginning with {@code "visit"}.
|
||||
*
|
||||
* <p>When such a new visit method is added, the default
|
||||
* implementation in this class will be to call the {@link
|
||||
* #visitUnknown visitUnknown} method. A new type kind visitor class
|
||||
* will also be introduced to correspond to the new language level;
|
||||
* this visitor will have different default behavior for the visit
|
||||
* method in question. When the new visitor is introduced, all or
|
||||
* portions of this visitor may be deprecated.
|
||||
*
|
||||
* @param <R> the return type of this visitor's methods. Use {@link
|
||||
* Void} for visitors that do not need to return results.
|
||||
* @param <P> the type of the additional parameter to this visitor's
|
||||
* methods. Use {@code Void} for visitors that do not need an
|
||||
* additional parameter.
|
||||
*
|
||||
* @see TypeKindVisitor6
|
||||
* @see TypeKindVisitor7
|
||||
* @see TypeKindVisitor8
|
||||
* @see TypeKindVisitor9
|
||||
* @since 14
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
public class TypeKindVisitor14<R, P> extends TypeKindVisitor9<R, P> {
|
||||
/**
|
||||
* Constructor for concrete subclasses to call; uses {@code null}
|
||||
* for the default value.
|
||||
*/
|
||||
protected TypeKindVisitor14() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for concrete subclasses to call; uses the argument
|
||||
* for the default value.
|
||||
*
|
||||
* @param defaultValue the value to assign to {@link #DEFAULT_VALUE}
|
||||
*/
|
||||
protected TypeKindVisitor14(R defaultValue) {
|
||||
super(defaultValue);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -75,6 +75,8 @@ import static javax.lang.model.SourceVersion.*;
|
||||
*
|
||||
* @see TypeKindVisitor7
|
||||
* @see TypeKindVisitor8
|
||||
* @see TypeKindVisitor9
|
||||
* @see TypeKindVisitor14
|
||||
* @since 1.6
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_6)
|
||||
|
@ -71,6 +71,8 @@ import javax.lang.model.SourceVersion;
|
||||
*
|
||||
* @see TypeKindVisitor6
|
||||
* @see TypeKindVisitor8
|
||||
* @see TypeKindVisitor9
|
||||
* @see TypeKindVisitor14
|
||||
* @since 1.7
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_7)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2019, 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
|
||||
@ -71,6 +71,8 @@ import static javax.lang.model.SourceVersion.*;
|
||||
*
|
||||
* @see TypeKindVisitor6
|
||||
* @see TypeKindVisitor7
|
||||
* @see TypeKindVisitor9
|
||||
* @see TypeKindVisitor14
|
||||
* @since 1.8
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_8)
|
||||
|
@ -75,6 +75,7 @@ import static javax.lang.model.SourceVersion.*;
|
||||
* @see TypeKindVisitor6
|
||||
* @see TypeKindVisitor7
|
||||
* @see TypeKindVisitor8
|
||||
* @see TypeKindVisitor14
|
||||
* @since 9
|
||||
*/
|
||||
@SupportedSourceVersion(RELEASE_14)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2019, 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 or NestMembers attribute";
|
||||
message = "class redefinition failed: attempted to change the class NestHost, NestMembers, or Record attribute";
|
||||
break;
|
||||
|
||||
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -29,7 +29,7 @@ import java.util.List;
|
||||
import javax.lang.model.element.Name;
|
||||
|
||||
/**
|
||||
* A tree node for a class, interface, enum, or annotation
|
||||
* A tree node for a class, interface, enum, record, or annotation
|
||||
* type declaration.
|
||||
*
|
||||
* For example:
|
||||
@ -44,6 +44,7 @@ import javax.lang.model.element.Name;
|
||||
*
|
||||
* @jls 8.1 Class Declarations
|
||||
* @jls 8.9 Enum Types
|
||||
* @jls 8.10 Record Types
|
||||
* @jls 9.1 Interface Declarations
|
||||
* @jls 9.6 Annotation Types
|
||||
*
|
||||
|
@ -648,6 +648,22 @@ public interface Tree {
|
||||
*/
|
||||
PROVIDES(ProvidesTree.class),
|
||||
|
||||
/**
|
||||
* {@preview Associated with records, a preview feature of the Java language.
|
||||
*
|
||||
* This enum constant is associated with <i>records</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.}
|
||||
*
|
||||
* Used for instances of {@link ClassTree} representing records.
|
||||
*
|
||||
* @since 14
|
||||
*/
|
||||
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
|
||||
essentialAPI=false)
|
||||
RECORD(ClassTree.class),
|
||||
|
||||
/**
|
||||
* Used for instances of {@link RequiresTree} representing
|
||||
* requires directives in a module declaration.
|
||||
|
@ -203,6 +203,7 @@ public class Checker extends DocTreePathScanner<Void, Void> {
|
||||
case INTERFACE:
|
||||
case ENUM:
|
||||
case ANNOTATION_TYPE:
|
||||
case RECORD:
|
||||
implicitHeadingRank = 1;
|
||||
break;
|
||||
|
||||
|
@ -420,10 +420,10 @@ public class JavacTrees extends DocTrees {
|
||||
|
||||
@Override @DefinedBy(Api.COMPILER_TREE)
|
||||
public Element getElement(DocTreePath path) {
|
||||
DocTree forTree = path.getLeaf();
|
||||
if (forTree instanceof DCReference)
|
||||
return attributeDocReference(path.getTreePath(), ((DCReference) forTree));
|
||||
if (forTree instanceof DCIdentifier) {
|
||||
DocTree tree = path.getLeaf();
|
||||
if (tree instanceof DCReference)
|
||||
return attributeDocReference(path.getTreePath(), ((DCReference) tree));
|
||||
if (tree instanceof DCIdentifier) {
|
||||
if (path.getParentPath().getLeaf() instanceof DCParam) {
|
||||
return attributeParamIdentifier(path.getTreePath(), (DCParam) path.getParentPath().getLeaf());
|
||||
}
|
||||
@ -536,7 +536,7 @@ public class JavacTrees extends DocTrees {
|
||||
}
|
||||
}
|
||||
|
||||
private Symbol attributeParamIdentifier(TreePath path, DCParam ptag) {
|
||||
private Symbol attributeParamIdentifier(TreePath path, DCParam paramTag) {
|
||||
Symbol javadocSymbol = getElement(path);
|
||||
if (javadocSymbol == null)
|
||||
return null;
|
||||
@ -544,16 +544,18 @@ public class JavacTrees extends DocTrees {
|
||||
List<? extends Symbol> params = List.nil();
|
||||
if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) {
|
||||
MethodSymbol ee = (MethodSymbol) javadocSymbol;
|
||||
params = ptag.isTypeParameter()
|
||||
params = paramTag.isTypeParameter()
|
||||
? ee.getTypeParameters()
|
||||
: ee.getParameters();
|
||||
} else if (kind.isClass() || kind.isInterface()) {
|
||||
ClassSymbol te = (ClassSymbol) javadocSymbol;
|
||||
params = te.getTypeParameters();
|
||||
params = paramTag.isTypeParameter()
|
||||
? te.getTypeParameters()
|
||||
: te.getRecordComponents();
|
||||
}
|
||||
|
||||
for (Symbol param : params) {
|
||||
if (param.getSimpleName() == ptag.getName().getName()) {
|
||||
if (param.getSimpleName() == paramTag.getName().getName()) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
|
@ -344,12 +344,35 @@ public class Flags {
|
||||
*/
|
||||
public static final long MATCH_BINDING_TO_OUTER = 1L<<60;
|
||||
|
||||
/**
|
||||
* Flag to indicate that a class is a record. The flag is also used to mark fields that are
|
||||
* part of the state vector of a record and to mark the canonical constructor
|
||||
*/
|
||||
public static final long RECORD = 1L<<61; // ClassSymbols, MethodSymbols and VarSymbols
|
||||
|
||||
/**
|
||||
* Flag to mark a record constructor as a compact one
|
||||
*/
|
||||
public static final long COMPACT_RECORD_CONSTRUCTOR = 1L<<51; // MethodSymbols only
|
||||
|
||||
/**
|
||||
* Flag to mark a record field that was not initialized in the compact constructor
|
||||
*/
|
||||
public static final long UNINITIALIZED_FIELD= 1L<<51; // VarSymbols only
|
||||
|
||||
/** Flag is set for compiler-generated record members, it could be appplied to
|
||||
* accessors and fields
|
||||
*/
|
||||
public static final int GENERATED_MEMBER = 1<<24; // MethodSymbols and VarSymbols
|
||||
|
||||
/** Modifier masks.
|
||||
*/
|
||||
public static final int
|
||||
AccessFlags = PUBLIC | PROTECTED | PRIVATE,
|
||||
LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
|
||||
LocalRecordFlags = LocalClassFlags | STATIC,
|
||||
MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags,
|
||||
MemberRecordFlags = MemberClassFlags | STATIC,
|
||||
ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
|
||||
InterfaceVarFlags = FINAL | STATIC | PUBLIC,
|
||||
VarFlags = AccessFlags | FINAL | STATIC |
|
||||
@ -357,6 +380,8 @@ public class Flags {
|
||||
ConstructorFlags = AccessFlags,
|
||||
InterfaceMethodFlags = ABSTRACT | PUBLIC,
|
||||
MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE |
|
||||
SYNCHRONIZED | FINAL | STRICTFP,
|
||||
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
|
||||
SYNCHRONIZED | FINAL | STRICTFP;
|
||||
public static final long
|
||||
ExtendedStandardFlags = (long)StandardFlags | DEFAULT,
|
||||
@ -465,7 +490,8 @@ public class Flags {
|
||||
PREVIEW_API(Flags.PREVIEW_API),
|
||||
PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API),
|
||||
MATCH_BINDING(Flags.MATCH_BINDING),
|
||||
MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER);
|
||||
MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER),
|
||||
RECORD(Flags.RECORD);
|
||||
|
||||
Flag(long flag) {
|
||||
this.value = flag;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2019, 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
|
||||
@ -235,7 +235,9 @@ public class Kinds {
|
||||
STATIC_INIT("kindname.static.init"),
|
||||
INSTANCE_INIT("kindname.instance.init"),
|
||||
PACKAGE("kindname.package"),
|
||||
MODULE("kindname.module");
|
||||
MODULE("kindname.module"),
|
||||
RECORD_COMPONENT("kindname.record.component"),
|
||||
RECORD("kindname.record");
|
||||
|
||||
private final String name;
|
||||
|
||||
@ -279,6 +281,9 @@ public class Kinds {
|
||||
case CLASS:
|
||||
return KindName.CLASS;
|
||||
|
||||
case RECORD:
|
||||
return KindName.RECORD;
|
||||
|
||||
case INTERFACE:
|
||||
return KindName.INTERFACE;
|
||||
|
||||
@ -286,13 +291,15 @@ public class Kinds {
|
||||
return KindName.TYPEVAR;
|
||||
|
||||
case ENUM_CONSTANT:
|
||||
case FIELD:
|
||||
case PARAMETER:
|
||||
case LOCAL_VARIABLE:
|
||||
case EXCEPTION_PARAMETER:
|
||||
case RESOURCE_VARIABLE:
|
||||
return KindName.VAR;
|
||||
|
||||
case FIELD:
|
||||
return ((sym.flags_field & RECORD) != 0) ? KindName.RECORD_COMPONENT : KindName.VAR;
|
||||
|
||||
case CONSTRUCTOR:
|
||||
return KindName.CONSTRUCTOR;
|
||||
|
||||
|
@ -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.TEXT_BLOCKS)
|
||||
feature == Feature.TEXT_BLOCKS ||
|
||||
feature == Feature.RECORDS)
|
||||
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'
|
||||
|
@ -201,6 +201,7 @@ public enum Source {
|
||||
TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL),
|
||||
PATTERN_MATCHING_IN_INSTANCEOF(JDK14, Fragments.FeaturePatternMatchingInstanceof, DiagKind.NORMAL),
|
||||
REIFIABLE_TYPES_INSTANCEOF(JDK14, Fragments.FeatureReifiableTypesInstanceof, DiagKind.PLURAL),
|
||||
RECORDS(JDK14, Fragments.FeatureRecords, DiagKind.PLURAL),
|
||||
;
|
||||
|
||||
enum DiagKind {
|
||||
|
@ -42,6 +42,7 @@ import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.ModuleElement;
|
||||
import javax.lang.model.element.NestingKind;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.lang.model.element.RecordComponentElement;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.TypeParameterElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
@ -61,17 +62,14 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
|
||||
import com.sun.tools.javac.tree.JCTree.Tag;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.DefinedBy.Api;
|
||||
import com.sun.tools.javac.util.List;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
import static com.sun.tools.javac.code.Flags.*;
|
||||
import static com.sun.tools.javac.code.Kinds.*;
|
||||
import static com.sun.tools.javac.code.Kinds.Kind.*;
|
||||
import com.sun.tools.javac.code.MissingInfoHandler;
|
||||
import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
|
||||
import com.sun.tools.javac.code.Scope.WriteableScope;
|
||||
import com.sun.tools.javac.code.Symbol;
|
||||
import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.FIRSTASGOP;
|
||||
import com.sun.tools.javac.code.Type;
|
||||
import static com.sun.tools.javac.code.TypeTag.CLASS;
|
||||
import static com.sun.tools.javac.code.TypeTag.FORALL;
|
||||
import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
|
||||
@ -80,7 +78,6 @@ import static com.sun.tools.javac.jvm.ByteCodes.ishll;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.lushrl;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.lxor;
|
||||
import static com.sun.tools.javac.jvm.ByteCodes.string_add;
|
||||
import com.sun.tools.javac.util.Name;
|
||||
|
||||
/** Root class for Java symbols. It contains subclasses
|
||||
* for specific sorts of symbols, such as variables, methods and operators,
|
||||
@ -406,15 +403,27 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
return (flags() & INTERFACE) != 0;
|
||||
}
|
||||
|
||||
public boolean isAbstract() {
|
||||
return (flags_field & ABSTRACT) != 0;
|
||||
}
|
||||
|
||||
public boolean isPrivate() {
|
||||
return (flags_field & Flags.AccessFlags) == PRIVATE;
|
||||
}
|
||||
|
||||
public boolean isPublic() {
|
||||
return (flags_field & Flags.AccessFlags) == PUBLIC;
|
||||
}
|
||||
|
||||
public boolean isEnum() {
|
||||
return (flags() & ENUM) != 0;
|
||||
}
|
||||
|
||||
/** Is this symbol declared (directly or indirectly) local
|
||||
public boolean isFinal() {
|
||||
return (flags_field & FINAL) != 0;
|
||||
}
|
||||
|
||||
/** Is this symbol declared (directly or indirectly) local
|
||||
* to a method or variable initializer?
|
||||
* Also includes fields of inner classes which are in
|
||||
* turn local to a method or variable initializer.
|
||||
@ -828,7 +837,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public java.util.List<Symbol> getEnclosedElements() {
|
||||
public List<Symbol> getEnclosedElements() {
|
||||
List<Symbol> list = List.nil();
|
||||
if (kind == TYP && type.hasTag(TYPEVAR)) {
|
||||
return list;
|
||||
@ -1264,6 +1273,8 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
/** the annotation metadata attached to this class */
|
||||
private AnnotationTypeMetadata annotationTypeMetadata;
|
||||
|
||||
private List<RecordComponent> recordComponents = List.nil();
|
||||
|
||||
public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
|
||||
super(TYP, flags, name, type, owner);
|
||||
this.members_field = null;
|
||||
@ -1332,6 +1343,18 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
return fullname;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public List<Symbol> getEnclosedElements() {
|
||||
List<Symbol> result = super.getEnclosedElements();
|
||||
if (!recordComponents.isEmpty()) {
|
||||
List<RecordComponent> reversed = recordComponents.reverse();
|
||||
for (RecordComponent rc : reversed) {
|
||||
result = result.prepend(rc);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Name flatName() {
|
||||
return flatname;
|
||||
}
|
||||
@ -1424,6 +1447,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@SuppressWarnings("preview")
|
||||
public ElementKind getKind() {
|
||||
apiComplete();
|
||||
long flags = flags();
|
||||
@ -1433,6 +1457,8 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
return ElementKind.INTERFACE;
|
||||
else if ((flags & ENUM) != 0)
|
||||
return ElementKind.ENUM;
|
||||
else if ((flags & RECORD) != 0)
|
||||
return ElementKind.RECORD;
|
||||
else
|
||||
return ElementKind.CLASS;
|
||||
}
|
||||
@ -1444,6 +1470,25 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
return Flags.asModifierSet(flags & ~DEFAULT);
|
||||
}
|
||||
|
||||
public RecordComponent getRecordComponent(VarSymbol field, boolean addIfMissing) {
|
||||
for (RecordComponent rc : recordComponents) {
|
||||
if (rc.name == field.name) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
RecordComponent rc = null;
|
||||
if (addIfMissing) {
|
||||
recordComponents = recordComponents.append(rc = new RecordComponent(PUBLIC, field.name, field.type, field.owner));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@SuppressWarnings("preview")
|
||||
public List<? extends RecordComponent> getRecordComponents() {
|
||||
return recordComponents;
|
||||
}
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public NestingKind getNestingKind() {
|
||||
apiComplete();
|
||||
@ -1457,7 +1502,6 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
return NestingKind.MEMBER;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected <A extends Annotation> Attribute.Compound getAttribute(final Class<A> annoType) {
|
||||
|
||||
@ -1473,9 +1517,6 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
: superType.getAttribute(annoType);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
|
||||
return v.visitType(this, p);
|
||||
@ -1534,6 +1575,10 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
Assert.check(!annotationTypeMetadata.isMetadataForAnnotationType());
|
||||
this.annotationTypeMetadata = a;
|
||||
}
|
||||
|
||||
public boolean isRecord() {
|
||||
return (flags_field & RECORD) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1681,6 +1726,35 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("preview")
|
||||
public static class RecordComponent extends VarSymbol implements RecordComponentElement {
|
||||
public MethodSymbol accessor;
|
||||
|
||||
/**
|
||||
* Construct a record component, given its flags, name, type and owner.
|
||||
*/
|
||||
public RecordComponent(long flags, Name name, Type type, Symbol owner) {
|
||||
super(flags, name, type, owner);
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@SuppressWarnings("preview")
|
||||
public ElementKind getKind() {
|
||||
return ElementKind.RECORD_COMPONENT;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public ExecutableElement getAccessor() {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
@Override @DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@SuppressWarnings("preview")
|
||||
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
|
||||
return v.visitRecordComponent(this, p);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParamSymbol extends VarSymbol {
|
||||
public ParamSymbol(long flags, Name name, Type type, Symbol owner) {
|
||||
super(flags, name, type, owner);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2019, 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
|
||||
@ -255,4 +255,36 @@ public class SymbolMetadata {
|
||||
private boolean isStarted() {
|
||||
return attributes != DECL_NOT_STARTED;
|
||||
}
|
||||
|
||||
private List<Attribute.Compound> removeFromCompoundList(List<Attribute.Compound> l, Attribute.Compound compound) {
|
||||
ListBuffer<Attribute.Compound> lb = new ListBuffer<>();
|
||||
for (Attribute.Compound c : l) {
|
||||
if (c != compound) {
|
||||
lb.add(c);
|
||||
}
|
||||
}
|
||||
return lb.toList();
|
||||
}
|
||||
|
||||
private List<Attribute.TypeCompound> removeFromTypeCompoundList(List<Attribute.TypeCompound> l, Attribute.TypeCompound compound) {
|
||||
ListBuffer<Attribute.TypeCompound> lb = new ListBuffer<>();
|
||||
for (Attribute.TypeCompound c : l) {
|
||||
if (c != compound) {
|
||||
lb.add(c);
|
||||
}
|
||||
}
|
||||
return lb.toList();
|
||||
}
|
||||
|
||||
public void remove(Attribute.Compound compound) {
|
||||
if (attributes.contains(compound)) {
|
||||
attributes = removeFromCompoundList(attributes, compound);
|
||||
} else if (type_attributes.contains(compound)) {
|
||||
type_attributes = removeFromTypeCompoundList(type_attributes, (TypeCompound)compound);
|
||||
} else if (init_type_attributes.contains(compound)) {
|
||||
init_type_attributes = removeFromTypeCompoundList(init_type_attributes, (TypeCompound)compound);
|
||||
} else if (clinit_type_attributes.contains(compound)) {
|
||||
clinit_type_attributes = removeFromTypeCompoundList(clinit_type_attributes, (TypeCompound)compound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -161,6 +161,7 @@ public class Symtab {
|
||||
/** Predefined types.
|
||||
*/
|
||||
public final Type objectType;
|
||||
public final Type objectMethodsType;
|
||||
public final Type objectsType;
|
||||
public final Type classType;
|
||||
public final Type classLoaderType;
|
||||
@ -215,6 +216,8 @@ public class Symtab {
|
||||
public final Type elementTypeType;
|
||||
public final Type functionalInterfaceType;
|
||||
public final Type previewFeatureType;
|
||||
public final Type typeDescriptorType;
|
||||
public final Type recordType;
|
||||
|
||||
/** The symbol representing the length field of an array.
|
||||
*/
|
||||
@ -509,6 +512,7 @@ public class Symtab {
|
||||
|
||||
// Enter predefined classes. All are assumed to be in the java.base module.
|
||||
objectType = enterClass("java.lang.Object");
|
||||
objectMethodsType = enterClass("java.lang.runtime.ObjectMethods");
|
||||
objectsType = enterClass("java.util.Objects");
|
||||
classType = enterClass("java.lang.Class");
|
||||
stringType = enterClass("java.lang.String");
|
||||
@ -572,6 +576,8 @@ public class Symtab {
|
||||
stringConcatFactory = enterClass("java.lang.invoke.StringConcatFactory");
|
||||
functionalInterfaceType = enterClass("java.lang.FunctionalInterface");
|
||||
previewFeatureType = enterClass("jdk.internal.PreviewFeature");
|
||||
typeDescriptorType = enterClass("java.lang.invoke.TypeDescriptor");
|
||||
recordType = enterClass("java.lang.Record");
|
||||
|
||||
synthesizeEmptyInterfaceIfMissing(autoCloseableType);
|
||||
synthesizeEmptyInterfaceIfMissing(cloneableType);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user