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:
Vicente Romero 2019-12-04 15:57:39 -05:00
parent 0a375cfa2d
commit 827e5e3226
351 changed files with 24958 additions and 6395 deletions

View File

@ -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. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # 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 \ ADD_JAVAC_FLAGS := --module-path $(BUILDTOOLS_OUTPUTDIR)/interim_langtools_modules \
$$(INTERIM_LANGTOOLS_ADD_EXPORTS) \ $$(INTERIM_LANGTOOLS_ADD_EXPORTS) \
--patch-module java.base=$(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim \ --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 \ --add-exports java.base/jdk.internal=jdk.compiler.interim \
-Xlint:-module, \ -Xlint:-module, \
)) ))

View File

@ -122,6 +122,7 @@ JVM_GetNestMembers
JVM_GetPrimitiveArrayElement JVM_GetPrimitiveArrayElement
JVM_GetProperties JVM_GetProperties
JVM_GetProtectionDomain JVM_GetProtectionDomain
JVM_GetRecordComponents
JVM_GetSimpleBinaryName JVM_GetSimpleBinaryName
JVM_GetStackAccessControlContext JVM_GetStackAccessControlContext
JVM_GetSystemPackage JVM_GetSystemPackage
@ -143,6 +144,7 @@ JVM_IsArrayClass
JVM_IsConstructorIx JVM_IsConstructorIx
JVM_IsInterface JVM_IsInterface
JVM_IsPrimitiveClass JVM_IsPrimitiveClass
JVM_IsRecord
JVM_IsSameClassPackage JVM_IsSameClassPackage
JVM_IsSupportedJNIVersion JVM_IsSupportedJNIVersion
JVM_IsThreadAlive JVM_IsThreadAlive

View File

@ -55,6 +55,7 @@
#include "oops/metadata.hpp" #include "oops/metadata.hpp"
#include "oops/method.inline.hpp" #include "oops/method.inline.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "oops/recordComponent.hpp"
#include "oops/symbol.hpp" #include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp" #include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp" #include "prims/jvmtiThreadState.hpp"
@ -3211,6 +3212,173 @@ u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream
return length; 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) { void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) {
set_class_synthetic_flag(true); set_class_synthetic_flag(true);
} }
@ -3308,6 +3476,12 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
CHECK); 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, void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
ConstantPool* cp, ConstantPool* cp,
ClassFileParser::ClassAnnotationCollector* parsed_annotations, ClassFileParser::ClassAnnotationCollector* parsed_annotations,
@ -3326,6 +3500,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
bool parsed_innerclasses_attribute = false; bool parsed_innerclasses_attribute = false;
bool parsed_nest_members_attribute = false; bool parsed_nest_members_attribute = false;
bool parsed_nest_host_attribute = false; bool parsed_nest_host_attribute = false;
bool parsed_record_attribute = false;
bool parsed_enclosingmethod_attribute = false; bool parsed_enclosingmethod_attribute = false;
bool parsed_bootstrap_methods_attribute = false; bool parsed_bootstrap_methods_attribute = false;
const u1* runtime_visible_annotations = NULL; 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; u2 enclosing_method_method_index = 0;
const u1* nest_members_attribute_start = NULL; const u1* nest_members_attribute_start = NULL;
u4 nest_members_attribute_length = 0; u4 nest_members_attribute_length = 0;
const u1* record_attribute_start = NULL;
u4 record_attribute_length = 0;
// Iterate over attributes // Iterate over attributes
while (attributes_count--) { 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", "Nest-host class_info_index %u has bad constant type in class file %s",
class_info_index, CHECK); class_info_index, CHECK);
_nest_host = class_info_index; _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 { } else {
// Unknown attribute // Unknown attribute
cfs->skip_u1(attribute_length, CHECK); 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) { if (_max_bootstrap_specifier_index >= 0) {
guarantee_property(parsed_bootstrap_methods_attribute, guarantee_property(parsed_bootstrap_methods_attribute,
"Missing BootstrapMethods attribute in class file %s", CHECK); "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. // Transfer ownership of metadata allocated to the InstanceKlass.
void ClassFileParser::apply_parsed_class_metadata( void ClassFileParser::apply_parsed_class_metadata(
InstanceKlass* this_klass, InstanceKlass* this_klass,
int java_fields_count, TRAPS) { int java_fields_count,
TRAPS) {
assert(this_klass != NULL, "invariant"); assert(this_klass != NULL, "invariant");
_cp->set_pool_holder(this_klass); _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_nest_host_index(_nest_host);
this_klass->set_local_interfaces(_local_interfaces); this_klass->set_local_interfaces(_local_interfaces);
this_klass->set_annotations(_combined_annotations); this_klass->set_annotations(_combined_annotations);
this_klass->set_record_components(_record_components);
// Delay the setting of _transitive_interfaces until after initialize_supers() in // Delay the setting of _transitive_interfaces until after initialize_supers() in
// fill_instance_klass(). It is because the _transitive_interfaces may be shared with // 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 // 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) { static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
assert(this_klass != NULL, "invariant"); assert(this_klass != NULL, "invariant");
const Klass* const super = this_klass->super(); const Klass* const super = this_klass->super();
if (super != NULL) { if (super != NULL) {
// If the loader is not the boot loader then throw an exception if its // 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_super = (flags & JVM_ACC_SUPER) != 0;
const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool is_enum = (flags & JVM_ACC_ENUM) != 0;
const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 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) || if ((is_abstract && is_final) ||
(is_interface && !is_abstract) || (is_interface && !is_abstract) ||
(is_interface && major_gte_15 && (is_super || is_enum)) || (is_interface && major_gte_1_5 && (is_super || is_enum)) ||
(!is_interface && major_gte_15 && is_annotation)) { (!is_interface && major_gte_1_5 && is_annotation)) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
Exceptions::fthrow( Exceptions::fthrow(
THREAD_AND_LOCATION, 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_volatile = (flags & JVM_ACC_VOLATILE) != 0;
const bool is_transient = (flags & JVM_ACC_TRANSIENT) != 0; const bool is_transient = (flags & JVM_ACC_TRANSIENT) != 0;
const bool is_enum = (flags & JVM_ACC_ENUM) != 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; bool is_illegal = false;
if (is_interface) { if (is_interface) {
if (!is_public || !is_static || !is_final || is_private || if (!is_public || !is_static || !is_final || is_private ||
is_protected || is_volatile || is_transient || is_protected || is_volatile || is_transient ||
(major_gte_15 && is_enum)) { (major_gte_1_5 && is_enum)) {
is_illegal = true; is_illegal = true;
} }
} else { // not interface } 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_strict = (flags & JVM_ACC_STRICT) != 0;
const bool is_synchronized = (flags & JVM_ACC_SYNCHRONIZED) != 0; const bool is_synchronized = (flags & JVM_ACC_SYNCHRONIZED) != 0;
const bool is_protected = (flags & JVM_ACC_PROTECTED) != 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 major_gte_8 = _major_version >= JAVA_8_VERSION;
const bool is_initializer = (name == vmSymbols::object_initializer_name()); 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_abstract && (is_private || is_static || is_strict))) {
is_illegal = true; 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) // Class file version in the interval [JAVA_1_5_VERSION, JAVA_8_VERSION)
if (!is_public || is_private || is_protected || is_static || is_final || if (!is_public || is_private || is_protected || is_static || is_final ||
is_synchronized || is_native || !is_abstract || is_strict) { is_synchronized || is_native || !is_abstract || is_strict) {
@ -4900,13 +5126,13 @@ void ClassFileParser::verify_legal_method_modifiers(jint flags,
} else { } else {
if (is_initializer) { if (is_initializer) {
if (is_static || is_final || is_synchronized || is_native || 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; is_illegal = true;
} }
} else { // not initializer } else { // not initializer
if (is_abstract) { if (is_abstract) {
if ((is_final || is_native || is_private || is_static || 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; 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 == _nest_members, "invariant");
assert(NULL == _local_interfaces, "invariant"); assert(NULL == _local_interfaces, "invariant");
assert(NULL == _combined_annotations, "invariant"); assert(NULL == _combined_annotations, "invariant");
assert(NULL == _record_components, "invariant");
if (_has_final_method) { if (_has_final_method) {
ik->set_has_final_method(); ik->set_has_final_method();
@ -5776,6 +6003,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_inner_classes(NULL), _inner_classes(NULL),
_nest_members(NULL), _nest_members(NULL),
_nest_host(0), _nest_host(0),
_record_components(NULL),
_local_interfaces(NULL), _local_interfaces(NULL),
_transitive_interfaces(NULL), _transitive_interfaces(NULL),
_combined_annotations(NULL), _combined_annotations(NULL),
@ -5886,6 +6114,7 @@ void ClassFileParser::clear_class_metadata() {
_combined_annotations = NULL; _combined_annotations = NULL;
_class_annotations = _class_type_annotations = NULL; _class_annotations = _class_type_annotations = NULL;
_fields_annotations = _fields_type_annotations = NULL; _fields_annotations = _fields_type_annotations = NULL;
_record_components = NULL;
} }
// Destructor to clean up // Destructor to clean up
@ -5913,6 +6142,10 @@ ClassFileParser::~ClassFileParser() {
MetadataFactory::free_array<u2>(_loader_data, _nest_members); MetadataFactory::free_array<u2>(_loader_data, _nest_members);
} }
if (_record_components != NULL) {
InstanceKlass::deallocate_record_components(_loader_data, _record_components);
}
// Free interfaces // Free interfaces
InstanceKlass::deallocate_interfaces(_loader_data, _super_klass, InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
_local_interfaces, _transitive_interfaces); _local_interfaces, _transitive_interfaces);

View File

@ -42,6 +42,7 @@ class FieldInfo;
template <typename T> template <typename T>
class GrowableArray; class GrowableArray;
class InstanceKlass; class InstanceKlass;
class RecordComponent;
class Symbol; class Symbol;
class TempNewSymbol; class TempNewSymbol;
@ -98,6 +99,7 @@ class ClassFileParser {
Array<u2>* _inner_classes; Array<u2>* _inner_classes;
Array<u2>* _nest_members; Array<u2>* _nest_members;
u2 _nest_host; u2 _nest_host;
Array<RecordComponent*>* _record_components;
Array<InstanceKlass*>* _local_interfaces; Array<InstanceKlass*>* _local_interfaces;
Array<InstanceKlass*>* _transitive_interfaces; Array<InstanceKlass*>* _transitive_interfaces;
Annotations* _combined_annotations; Annotations* _combined_annotations;
@ -287,6 +289,13 @@ class ClassFileParser {
const u1* const nest_members_attribute_start, const u1* const nest_members_attribute_start,
TRAPS); 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, void parse_classfile_attributes(const ClassFileStream* const cfs,
ConstantPool* cp, ConstantPool* cp,
ClassAnnotationCollector* parsed_annotations, ClassAnnotationCollector* parsed_annotations,

View File

@ -50,6 +50,7 @@
#include "oops/objArrayOop.inline.hpp" #include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "oops/symbol.hpp" #include "oops/symbol.hpp"
#include "oops/recordComponent.hpp"
#include "oops/typeArrayOop.inline.hpp" #include "oops/typeArrayOop.inline.hpp"
#include "prims/jvmtiExport.hpp" #include "prims/jvmtiExport.hpp"
#include "prims/resolvedMethodTable.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); 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) \ #define CONSTANTPOOL_FIELDS_DO(macro) \
macro(_oop_offset, k, "constantPoolOop", object_signature, false) 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_Byte_ByteCache::_static_cache_offset;
int java_lang_Boolean::_static_TRUE_offset; int java_lang_Boolean::_static_TRUE_offset;
int java_lang_Boolean::_static_FALSE_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(); 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 // Compute hard-coded offsets
// Invoked before SystemDictionary::initialize, so pre-loaded classes // Invoked before SystemDictionary::initialize, so pre-loaded classes
// are not available to determine the offset_of_static_fields. // are not available to determine the offset_of_static_fields.

View File

@ -30,6 +30,8 @@
#include "oops/oop.hpp" #include "oops/oop.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
class RecordComponent;
// Interface for manipulating the basic Java classes. // Interface for manipulating the basic Java classes.
// //
// All dependencies on layout of actual Java classes should be kept here. // 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_Method) \
f(java_lang_reflect_Constructor) \ f(java_lang_reflect_Constructor) \
f(java_lang_reflect_Field) \ f(java_lang_reflect_Field) \
f(java_lang_reflect_RecordComponent) \
f(java_nio_Buffer) \ f(java_nio_Buffer) \
f(reflect_ConstantPool) \ f(reflect_ConstantPool) \
f(reflect_UnsafeStaticFieldAccessorImpl) \ f(reflect_UnsafeStaticFieldAccessorImpl) \
@ -1483,6 +1486,39 @@ class java_lang_LiveStackFrameInfo: AllStatic {
friend class JavaClasses; 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 // Interface to java.lang.AssertionStatusDirectives objects
class java_lang_AssertionStatusDirectives: AllStatic { class java_lang_AssertionStatusDirectives: AllStatic {

View File

@ -119,6 +119,7 @@ class GCTimer;
do_klass(AccessController_klass, java_security_AccessController ) \ do_klass(AccessController_klass, java_security_AccessController ) \
do_klass(SecureClassLoader_klass, java_security_SecureClassLoader ) \ do_klass(SecureClassLoader_klass, java_security_SecureClassLoader ) \
do_klass(ClassNotFoundException_klass, java_lang_ClassNotFoundException ) \ do_klass(ClassNotFoundException_klass, java_lang_ClassNotFoundException ) \
do_klass(Record_klass, java_lang_Record ) \
do_klass(NoClassDefFoundError_klass, java_lang_NoClassDefFoundError ) \ do_klass(NoClassDefFoundError_klass, java_lang_NoClassDefFoundError ) \
do_klass(LinkageError_klass, java_lang_LinkageError ) \ do_klass(LinkageError_klass, java_lang_LinkageError ) \
do_klass(ClassCastException_klass, java_lang_ClassCastException ) \ do_klass(ClassCastException_klass, java_lang_ClassCastException ) \
@ -217,6 +218,9 @@ class GCTimer;
/* force inline of iterators */ \ /* force inline of iterators */ \
do_klass(Iterator_klass, java_util_Iterator ) \ do_klass(Iterator_klass, java_util_Iterator ) \
\ \
/* support for records */ \
do_klass(RecordComponent_klass, java_lang_reflect_RecordComponent ) \
\
/*end*/ /*end*/
class SystemDictionary : AllStatic { class SystemDictionary : AllStatic {

View File

@ -94,6 +94,7 @@
template(java_lang_reflect_Field, "java/lang/reflect/Field") \ template(java_lang_reflect_Field, "java/lang/reflect/Field") \
template(java_lang_reflect_Parameter, "java/lang/reflect/Parameter") \ template(java_lang_reflect_Parameter, "java/lang/reflect/Parameter") \
template(java_lang_reflect_Array, "java/lang/reflect/Array") \ 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_StringBuffer, "java/lang/StringBuffer") \
template(java_lang_StringBuilder, "java/lang/StringBuilder") \ template(java_lang_StringBuilder, "java/lang/StringBuilder") \
template(java_lang_CharSequence, "java/lang/CharSequence") \ template(java_lang_CharSequence, "java/lang/CharSequence") \
@ -127,6 +128,7 @@
template(jdk_internal_vm_PostVMInitHook, "jdk/internal/vm/PostVMInitHook") \ template(jdk_internal_vm_PostVMInitHook, "jdk/internal/vm/PostVMInitHook") \
template(sun_net_www_ParseUtil, "sun/net/www/ParseUtil") \ template(sun_net_www_ParseUtil, "sun/net/www/ParseUtil") \
template(java_util_Iterator, "java/util/Iterator") \ 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_AppClassLoader, "jdk/internal/loader/ClassLoaders$AppClassLoader") \
template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \ template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \
@ -161,6 +163,7 @@
template(tag_deprecated, "Deprecated") \ template(tag_deprecated, "Deprecated") \
template(tag_source_debug_extension, "SourceDebugExtension") \ template(tag_source_debug_extension, "SourceDebugExtension") \
template(tag_signature, "Signature") \ template(tag_signature, "Signature") \
template(tag_record, "Record") \
template(tag_runtime_visible_annotations, "RuntimeVisibleAnnotations") \ template(tag_runtime_visible_annotations, "RuntimeVisibleAnnotations") \
template(tag_runtime_invisible_annotations, "RuntimeInvisibleAnnotations") \ template(tag_runtime_invisible_annotations, "RuntimeInvisibleAnnotations") \
template(tag_runtime_visible_parameter_annotations, "RuntimeVisibleParameterAnnotations") \ template(tag_runtime_visible_parameter_annotations, "RuntimeVisibleParameterAnnotations") \
@ -562,6 +565,7 @@
template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \ template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \
template(int_String_signature, "(I)Ljava/lang/String;") \ template(int_String_signature, "(I)Ljava/lang/String;") \
template(boolean_boolean_int_signature, "(ZZ)I") \ template(boolean_boolean_int_signature, "(ZZ)I") \
template(reflect_method_signature, "Ljava/lang/reflect/Method;") \
/* signature symbols needed by intrinsics */ \ /* signature symbols needed by intrinsics */ \
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \
\ \

View File

@ -518,6 +518,7 @@ JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass, jboolean publicOnly);
JNIEXPORT jobjectArray JNICALL JNIEXPORT jobjectArray JNICALL
JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly); JVM_GetClassDeclaredConstructors(JNIEnv *env, jclass ofClass, jboolean publicOnly);
/* Differs from JVM_GetClassModifiers in treatment of inner classes. /* Differs from JVM_GetClassModifiers in treatment of inner classes.
This returns the access flags for the class as specified in the This returns the access flags for the class as specified in the
class file rather than searching the InnerClasses attribute (if class file rather than searching the InnerClasses attribute (if
@ -538,6 +539,14 @@ JVM_GetNestHost(JNIEnv *env, jclass current);
JNIEXPORT jobjectArray JNICALL JNIEXPORT jobjectArray JNICALL
JVM_GetNestMembers(JNIEnv *env, jclass current); 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 */ /* The following two reflection routines are still needed due to startup time issues */
/* /*
* java.lang.reflect.Method * java.lang.reflect.Method

View File

@ -137,6 +137,7 @@
LOG_TAG(parser) \ LOG_TAG(parser) \
LOG_TAG(ptrqueue) \ LOG_TAG(ptrqueue) \
LOG_TAG(purge) \ LOG_TAG(purge) \
LOG_TAG(record) \
LOG_TAG(resolve) \ LOG_TAG(resolve) \
LOG_TAG(safepoint) \ LOG_TAG(safepoint) \
LOG_TAG(sampling) \ LOG_TAG(sampling) \

View File

@ -300,7 +300,8 @@ class MetaspaceObj {
f(ConstantPool) \ f(ConstantPool) \
f(ConstantPoolCache) \ f(ConstantPoolCache) \
f(Annotations) \ f(Annotations) \
f(MethodCounters) f(MethodCounters) \
f(RecordComponent)
#define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type, #define METASPACE_OBJ_TYPE_DECLARE(name) name ## Type,
#define METASPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name; #define METASPACE_OBJ_TYPE_NAME_CASE(name) case name ## Type: return #name;

View File

@ -88,6 +88,8 @@
"Number of bytes used by the InstanceKlass::inner_classes() array") \ "Number of bytes used by the InstanceKlass::inner_classes() array") \
f(nest_members_bytes, IK_nest_members, \ f(nest_members_bytes, IK_nest_members, \
"Number of bytes used by the InstanceKlass::nest_members() array") \ "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, \ f(signers_bytes, IK_signers, \
"Number of bytes used by the InstanceKlass::singers() array") \ "Number of bytes used by the InstanceKlass::singers() array") \
f(class_annotations_bytes, class_annotations, \ f(class_annotations_bytes, class_annotations, \

View File

@ -823,6 +823,7 @@ intptr_t* MetaspaceShared::fix_cpp_vtable_for_dynamic_archive(MetaspaceObj::Type
case MetaspaceObj::ConstantPoolCacheType: case MetaspaceObj::ConstantPoolCacheType:
case MetaspaceObj::AnnotationsType: case MetaspaceObj::AnnotationsType:
case MetaspaceObj::MethodCountersType: case MetaspaceObj::MethodCountersType:
case MetaspaceObj::RecordComponentType:
// These have no vtables. // These have no vtables.
break; break;
case MetaspaceObj::ClassType: case MetaspaceObj::ClassType:

View File

@ -63,6 +63,7 @@
#include "oops/klass.inline.hpp" #include "oops/klass.inline.hpp"
#include "oops/method.hpp" #include "oops/method.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "oops/recordComponent.hpp"
#include "oops/symbol.hpp" #include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp" #include "prims/jvmtiExport.hpp"
#include "prims/jvmtiRedefineClasses.hpp" #include "prims/jvmtiRedefineClasses.hpp"
@ -436,6 +437,7 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass
_nest_members(NULL), _nest_members(NULL),
_nest_host_index(0), _nest_host_index(0),
_nest_host(NULL), _nest_host(NULL),
_record_components(NULL),
_static_field_size(parser.static_field_size()), _static_field_size(parser.static_field_size()),
_nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())), _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
_itable_len(parser.itable_size()), _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 // This function deallocates the metadata and C heap pointers that the
// InstanceKlass points to. // InstanceKlass points to.
void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
@ -532,6 +545,9 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
deallocate_methods(loader_data, methods()); deallocate_methods(loader_data, methods());
set_methods(NULL); set_methods(NULL);
deallocate_record_components(loader_data, record_components());
set_record_components(NULL);
if (method_ordering() != NULL && if (method_ordering() != NULL &&
method_ordering() != Universe::the_empty_int_array() && method_ordering() != Universe::the_empty_int_array() &&
!method_ordering()->is_shared()) { !method_ordering()->is_shared()) {
@ -2339,6 +2355,7 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) {
} }
it->push(&_nest_members); it->push(&_nest_members);
it->push(&_record_components);
} }
void InstanceKlass::remove_unshareable_info() { 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"inner classes: "); inner_classes()->print_value_on(st); st->cr();
st->print(BULLET"nest members: "); nest_members()->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) { if (java_mirror() != NULL) {
st->print(BULLET"java mirror: "); st->print(BULLET"java mirror: ");
java_mirror()->print_value_on(st); 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->_fields_bytes = sz->count_array(fields()));
n += (sz->_inner_classes_bytes = sz->count_array(inner_classes())); n += (sz->_inner_classes_bytes = sz->count_array(inner_classes()));
n += (sz->_nest_members_bytes = sz->count_array(nest_members())); n += (sz->_nest_members_bytes = sz->count_array(nest_members()));
n += (sz->_record_components_bytes = sz->count_array(record_components()));
sz->_ro_bytes += n; sz->_ro_bytes += n;
const ConstantPool* cp = constants(); 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 #endif // INCLUDE_SERVICES

View File

@ -41,6 +41,7 @@
#include "jfr/support/jfrKlassExtension.hpp" #include "jfr/support/jfrKlassExtension.hpp"
#endif #endif
class RecordComponent;
// An InstanceKlass is the VM level representation of a Java class. // An InstanceKlass is the VM level representation of a Java class.
// It contains all information needed for at class at execution runtime. // 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. // By always being set it makes nest-member access checks simpler.
InstanceKlass* _nest_host; InstanceKlass* _nest_host;
// The contents of the Record attribute.
Array<RecordComponent*>* _record_components;
// the source debug extension for this klass, NULL if not specified. // the source debug extension for this klass, NULL if not specified.
// Specified as UTF-8 string without terminating zero byte in the classfile, // 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 // 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; } jushort nest_host_index() const { return _nest_host_index; }
void set_nest_host_index(u2 i) { _nest_host_index = i; } 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: private:
// Called to verify that k is a member of this nest - does not look at k's nest-host // 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; bool has_nest_member(InstanceKlass* k, TRAPS) const;
public: public:
// Returns nest-host class, resolving and validating it if needed // Returns nest-host class, resolving and validating it if needed
// Returns NULL if an exception occurs during loading, or validation fails // Returns NULL if an exception occurs during loading, or validation fails
@ -1152,6 +1164,8 @@ public:
const Klass* super_klass, const Klass* super_klass,
Array<InstanceKlass*>* local_interfaces, Array<InstanceKlass*>* local_interfaces,
Array<InstanceKlass*>* transitive_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 // The constant pool is on stack if any of the methods are executing or
// referenced by handles. // referenced by handles.

View 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

View 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

View File

@ -51,6 +51,7 @@
#include "oops/fieldStreams.inline.hpp" #include "oops/fieldStreams.inline.hpp"
#include "oops/instanceKlass.hpp" #include "oops/instanceKlass.hpp"
#include "oops/method.hpp" #include "oops/method.hpp"
#include "oops/recordComponent.hpp"
#include "oops/objArrayKlass.hpp" #include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp" #include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
@ -1693,6 +1694,54 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
} }
JVM_END 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) { static bool select_method(const methodHandle& method, bool want_constructor) {
if (want_constructor) { if (want_constructor) {
return (method->is_initializer() && !method->is_static()); return (method->is_initializer() && !method->is_static());

View File

@ -7633,8 +7633,8 @@ class C2 extends C1 implements I2 {
(unless explicitly prohibited). (unless explicitly prohibited).
The retransformation must not add, remove or rename fields or methods, change the The retransformation must not add, remove or rename fields or methods, change the
signatures of methods, change modifiers, or change inheritance. signatures of methods, change modifiers, or change inheritance.
The retransformation must not change the <code>NestHost</code> or The retransformation must not change the <code>NestHost</code>,
<code>NestMembers</code> attributes. <code>NestMembers</code>, or <code>Record</code> attributes.
These restrictions may be lifted in future versions. These restrictions may be lifted in future versions.
See the error return description below for information on error codes See the error return description below for information on error codes
returned if an unsupported retransformation is attempted. returned if an unsupported retransformation is attempted.
@ -7786,8 +7786,8 @@ class C2 extends C1 implements I2 {
(unless explicitly prohibited). (unless explicitly prohibited).
The redefinition must not add, remove or rename fields or methods, change the The redefinition must not add, remove or rename fields or methods, change the
signatures of methods, change modifiers, or change inheritance. signatures of methods, change modifiers, or change inheritance.
The retransformation must not change the <code>NestHost</code> or The redefinition must not change the <code>NestHost</code>,
<code>NestMembers</code> attributes. <code>NestMembers</code>, or <code>Record</code> attributes.
These restrictions may be lifted in future versions. These restrictions may be lifted in future versions.
See the error return description below for information on error codes See the error return description below for information on error codes
returned if an unsupported redefinition is attempted. returned if an unsupported redefinition is attempted.
@ -14974,6 +14974,11 @@ typedef void (JNICALL *jvmtiEventVMInit)
- The specified thread must be suspended or must be the current thread. - The specified thread must be suspended or must be the current thread.
(It was not allowed to be the current thread before.) (It was not allowed to be the current thread before.)
</change> </change>
<change date="10 October 2019" version="14.0.0">
Minor update for new class file Record attribute:
- Specify that RedefineClasses and RetransformClasses are not allowed
to change the class file Record attribute.
</change>
</changehistory> </changehistory>
</specification> </specification>

View File

@ -27,6 +27,7 @@
#include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodeStream.hpp"
#include "memory/universe.hpp" #include "memory/universe.hpp"
#include "oops/fieldStreams.inline.hpp" #include "oops/fieldStreams.inline.hpp"
#include "oops/recordComponent.hpp"
#include "prims/jvmtiClassFileReconstituter.hpp" #include "prims/jvmtiClassFileReconstituter.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/signature.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 // Write InnerClasses attribute
// JVMSpec| InnerClasses_attribute { // JVMSpec| InnerClasses_attribute {
@ -699,6 +751,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if (ik()->nest_members() != Universe::the_empty_short_array()) { if (ik()->nest_members() != Universe::the_empty_short_array()) {
++attr_count; ++attr_count;
} }
if (ik()->record_components() != NULL) {
++attr_count;
}
write_u2(attr_count); write_u2(attr_count);
@ -729,6 +784,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if (ik()->nest_members() != Universe::the_empty_short_array()) { if (ik()->nest_members() != Universe::the_empty_short_array()) {
write_nest_members_attribute(); write_nest_members_attribute();
} }
if (ik()->record_components() != NULL) {
write_record_attribute();
}
} }
// Write the method information portion of ClassFile structure // Write the method information portion of ClassFile structure

View File

@ -118,6 +118,7 @@ class JvmtiClassFileReconstituter : public JvmtiConstantPoolReconstituter {
void write_bootstrapmethod_attribute(); void write_bootstrapmethod_attribute();
void write_nest_host_attribute(); void write_nest_host_attribute();
void write_nest_members_attribute(); void write_nest_members_attribute();
void write_record_attribute();
address writeable_address(size_t size); address writeable_address(size_t size);
void write_u1(u1 x); void write_u1(u1 x);

View File

@ -40,10 +40,12 @@
#include "memory/metaspaceShared.hpp" #include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "memory/universe.hpp" #include "memory/universe.hpp"
#include "oops/annotations.hpp"
#include "oops/constantPool.hpp" #include "oops/constantPool.hpp"
#include "oops/fieldStreams.inline.hpp" #include "oops/fieldStreams.inline.hpp"
#include "oops/klassVtable.hpp" #include "oops/klassVtable.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "oops/recordComponent.hpp"
#include "prims/jvmtiImpl.hpp" #include "prims/jvmtiImpl.hpp"
#include "prims/jvmtiRedefineClasses.hpp" #include "prims/jvmtiRedefineClasses.hpp"
#include "prims/jvmtiThreadState.inline.hpp" #include "prims/jvmtiThreadState.inline.hpp"
@ -785,6 +787,69 @@ static jvmtiError check_nest_attributes(InstanceKlass* the_class,
return JVMTI_ERROR_NONE; 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) { static bool can_add_or_delete(Method* m) {
// Compatibility mode // Compatibility mode
return (AllowRedefinitionToAddDeleteMethods && return (AllowRedefinitionToAddDeleteMethods &&
@ -838,6 +903,12 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
return err; 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. // Check whether class modifiers are the same.
jushort old_flags = (jushort) the_class->access_flags().get_flags(); jushort old_flags = (jushort) the_class->access_flags().get_flags();
jushort new_flags = (jushort) scratch_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; 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: // rewrite constant pool references in the methods:
if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) { if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) {
// propagate failure back to caller // propagate failure back to caller
@ -1809,6 +1886,46 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_nest_attributes(
return true; 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. // Rewrite constant pool references in the methods.
bool VM_RedefineClasses::rewrite_cp_refs_in_methods( bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
InstanceKlass* scratch_class, TRAPS) { InstanceKlass* scratch_class, TRAPS) {

View File

@ -472,6 +472,7 @@ class VM_RedefineClasses: public VM_Operation {
bool rewrite_cp_refs_in_fields_annotations( bool rewrite_cp_refs_in_fields_annotations(
InstanceKlass* scratch_class, TRAPS); InstanceKlass* scratch_class, TRAPS);
bool rewrite_cp_refs_in_nest_attributes(InstanceKlass* scratch_class); 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, void rewrite_cp_refs_in_method(methodHandle method,
methodHandle * new_method_p, TRAPS); methodHandle * new_method_p, TRAPS);
bool rewrite_cp_refs_in_methods(InstanceKlass* scratch_class, TRAPS); bool rewrite_cp_refs_in_methods(InstanceKlass* scratch_class, TRAPS);

View File

@ -26,7 +26,9 @@
package java.io; package java.io;
import java.io.ObjectStreamClass.WeakClassKey; import java.io.ObjectStreamClass.WeakClassKey;
import java.io.ObjectStreamClass.RecordSupport;
import java.lang.System.Logger; import java.lang.System.Logger;
import java.lang.invoke.MethodHandle;
import java.lang.ref.ReferenceQueue; import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@ -218,6 +220,39 @@ import sun.reflect.misc.ReflectUtil;
* Similarly, any serialPersistentFields or serialVersionUID field declarations * Similarly, any serialPersistentFields or serialVersionUID field declarations
* are also ignored--all enum types have a fixed serialVersionUID of 0L. * 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 Mike Warres
* @author Roger Riggs * @author Roger Riggs
* @see java.io.DataInput * @see java.io.DataInput
@ -2047,6 +2082,11 @@ public class ObjectInputStream
return result; return result;
} }
@SuppressWarnings("preview")
private static boolean isRecord(Class<?> cls) {
return cls.isRecord();
}
/** /**
* Reads and returns "ordinary" (i.e., not a String, Class, * Reads and returns "ordinary" (i.e., not a String, Class,
* ObjectStreamClass, array, or enum constant) object, or null if object's * ObjectStreamClass, array, or enum constant) object, or null if object's
@ -2085,7 +2125,12 @@ public class ObjectInputStream
handles.markException(passHandle, resolveEx); 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); readExternalData((Externalizable) obj, desc);
} else { } else {
readSerialData(obj, desc); 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 * Reads (or attempts to skip, if obj is null or is tagged with a
* ClassNotFoundException) instance data for each serializable class of * 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 byte[] primValues;
final Object[] objValues; final Object[] objValues;

View File

@ -150,6 +150,10 @@ import sun.reflect.misc.ReflectUtil;
* defaultWriteObject and writeFields initially terminate any existing * defaultWriteObject and writeFields initially terminate any existing
* block-data record. * 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 Mike Warres
* @author Roger Riggs * @author Roger Riggs
* @see java.io.DataOutput * @see java.io.DataOutput
@ -1431,7 +1435,10 @@ public class ObjectOutputStream
bout.writeByte(TC_OBJECT); bout.writeByte(TC_OBJECT);
writeClassDesc(desc, false); writeClassDesc(desc, false);
handles.assign(unshared ? null : obj); 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); writeExternalData((Externalizable) obj);
} else { } else {
writeSerialData(obj, desc); writeSerialData(obj, desc);
@ -1475,6 +1482,21 @@ public class ObjectOutputStream
curPut = oldPut; 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 * Writes instance data for each serializable class of given object, from
* superclass to subclass. * superclass to subclass.

View File

@ -25,6 +25,8 @@
package java.io; package java.io;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.ref.Reference; import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue; import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
@ -32,6 +34,7 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.RecordComponent;
import java.lang.reflect.UndeclaredThrowableException; import java.lang.reflect.UndeclaredThrowableException;
import java.lang.reflect.Member; import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -44,6 +47,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.PermissionCollection; import java.security.PermissionCollection;
import java.security.Permissions; import java.security.Permissions;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -123,6 +128,8 @@ public class ObjectStreamClass implements Serializable {
private boolean isProxy; private boolean isProxy;
/** true if represents enum type */ /** true if represents enum type */
private boolean isEnum; private boolean isEnum;
/** true if represents record type */
private boolean isRecord;
/** true if represented class implements Serializable */ /** true if represented class implements Serializable */
private boolean serializable; private boolean serializable;
/** true if represented class implements Externalizable */ /** true if represented class implements Externalizable */
@ -184,6 +191,8 @@ public class ObjectStreamClass implements Serializable {
/** serialization-appropriate constructor, or null if none */ /** serialization-appropriate constructor, or null if none */
private Constructor<?> cons; private Constructor<?> cons;
/** record canonical constructor, or null */
private MethodHandle canonicalCtr;
/** protection domains that need to be checked when calling the constructor */ /** protection domains that need to be checked when calling the constructor */
private ProtectionDomain[] domains; private ProtectionDomain[] domains;
@ -261,6 +270,9 @@ public class ObjectStreamClass implements Serializable {
public long getSerialVersionUID() { public long getSerialVersionUID() {
// REMIND: synchronize instead of relying on volatile? // REMIND: synchronize instead of relying on volatile?
if (suid == null) { if (suid == null) {
if (isRecord)
return 0L;
suid = AccessController.doPrivileged( suid = AccessController.doPrivileged(
new PrivilegedAction<Long>() { new PrivilegedAction<Long>() {
public Long run() { 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. * Creates local class descriptor representing given class.
*/ */
@ -475,6 +492,7 @@ public class ObjectStreamClass implements Serializable {
name = cl.getName(); name = cl.getName();
isProxy = Proxy.isProxyClass(cl); isProxy = Proxy.isProxyClass(cl);
isEnum = Enum.class.isAssignableFrom(cl); isEnum = Enum.class.isAssignableFrom(cl);
isRecord = isRecord(cl);
serializable = Serializable.class.isAssignableFrom(cl); serializable = Serializable.class.isAssignableFrom(cl);
externalizable = Externalizable.class.isAssignableFrom(cl); externalizable = Externalizable.class.isAssignableFrom(cl);
@ -505,7 +523,9 @@ public class ObjectStreamClass implements Serializable {
fields = NO_FIELDS; fields = NO_FIELDS;
} }
if (externalizable) { if (isRecord) {
canonicalCtr = canonicalRecordCtr(cl);
} else if (externalizable) {
cons = getExternalizableConstructor(cl); cons = getExternalizableConstructor(cl);
} else { } else {
cons = getSerializableConstructor(cl); cons = getSerializableConstructor(cl);
@ -542,16 +562,20 @@ public class ObjectStreamClass implements Serializable {
if (deserializeEx == null) { if (deserializeEx == null) {
if (isEnum) { if (isEnum) {
deserializeEx = new ExceptionInfo(name, "enum type"); deserializeEx = new ExceptionInfo(name, "enum type");
} else if (cons == null) { } else if (cons == null && !isRecord) {
deserializeEx = new ExceptionInfo(name, "no valid constructor"); deserializeEx = new ExceptionInfo(name, "no valid constructor");
} }
} }
if (isRecord && canonicalCtr == null) {
deserializeEx = new ExceptionInfo(name, "record canonical constructor not found");
} else {
for (int i = 0; i < fields.length; i++) { for (int i = 0; i < fields.length; i++) {
if (fields[i].getField() == null) { if (fields[i].getField() == null) {
defaultSerializeEx = new ExceptionInfo( defaultSerializeEx = new ExceptionInfo(
name, "unmatched serializable field(s) declared"); name, "unmatched serializable field(s) declared");
} }
} }
}
initialized = true; initialized = true;
} }
@ -682,7 +706,7 @@ public class ObjectStreamClass implements Serializable {
} }
if (model.serializable == osc.serializable && if (model.serializable == osc.serializable &&
!cl.isArray() && !cl.isArray() && !isRecord(cl) &&
suid != osc.getSerialVersionUID()) { suid != osc.getSerialVersionUID()) {
throw new InvalidClassException(osc.name, throw new InvalidClassException(osc.name,
"local class incompatible: " + "local class incompatible: " +
@ -714,6 +738,10 @@ public class ObjectStreamClass implements Serializable {
} }
this.cl = cl; this.cl = cl;
if (cl != null) {
this.isRecord = isRecord(cl);
this.canonicalCtr = osc.canonicalCtr;
}
this.resolveEx = resolveEx; this.resolveEx = resolveEx;
this.superDesc = superDesc; this.superDesc = superDesc;
name = model.name; name = model.name;
@ -739,12 +767,14 @@ public class ObjectStreamClass implements Serializable {
deserializeEx = localDesc.deserializeEx; deserializeEx = localDesc.deserializeEx;
} }
domains = localDesc.domains; domains = localDesc.domains;
assert isRecord(cl) ? localDesc.cons == null : true;
cons = localDesc.cons; cons = localDesc.cons;
} }
fieldRefl = getReflector(fields, localDesc); fieldRefl = getReflector(fields, localDesc);
// reassign to matched fields so as to reflect local unshared settings // reassign to matched fields so as to reflect local unshared settings
fields = fieldRefl.getFields(); fields = fieldRefl.getFields();
initialized = true; initialized = true;
} }
@ -966,6 +996,15 @@ public class ObjectStreamClass implements Serializable {
return isEnum; 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 * Returns true if represented class implements Externalizable, false
* otherwise. * otherwise.
@ -1518,6 +1557,37 @@ public class ObjectStreamClass implements Serializable {
return reflFactory.newConstructorForSerialization(cl); 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 * Returns non-static, non-abstract method with given signature provided it
* is defined by or accessible (via inheritance) by the given class, or * 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) private static ObjectStreamField[] getSerialFields(Class<?> cl)
throws InvalidClassException throws InvalidClassException
{ {
if (!Serializable.class.isAssignableFrom(cl))
return NO_FIELDS;
ObjectStreamField[] fields; ObjectStreamField[] fields;
if (Serializable.class.isAssignableFrom(cl) && if (isRecord(cl)) {
!Externalizable.class.isAssignableFrom(cl) && fields = getDefaultSerialFields(cl);
Arrays.sort(fields);
} else if (!Externalizable.class.isAssignableFrom(cl) &&
!Proxy.isProxyClass(cl) && !Proxy.isProxyClass(cl) &&
!cl.isInterface()) !cl.isInterface()) {
{
if ((fields = getDeclaredSerialFields(cl)) == null) { if ((fields = getDeclaredSerialFields(cl)) == null) {
fields = getDefaultSerialFields(cl); 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);
}
}
} }

View File

@ -46,6 +46,7 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.lang.reflect.RecordComponent;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable; import java.lang.reflect.TypeVariable;
import java.lang.constant.Constable; import java.lang.constant.Constable;
@ -2259,6 +2260,68 @@ public final class Class<T> implements java.io.Serializable,
return copyFields(privateGetDeclaredFields(false)); 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 * 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 Method[] getDeclaredMethods0(boolean publicOnly);
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly); private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
private native Class<?>[] getDeclaredClasses0(); private native Class<?>[] getDeclaredClasses0();
private native Object[] getRecordComponents0();
private native boolean isRecord0();
/** /**
* Helper method to get the method name from arguments. * 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; 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 // Fetches the factory for reflective objects
private static ReflectionFactory getReflectionFactory() { private static ReflectionFactory getReflectionFactory() {
if (reflectionFactory == null) { if (reflectionFactory == null) {

View 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&trade; 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&trade;
* 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();
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -114,5 +114,25 @@ public enum ElementType {
* *
* @since 9 * @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;
} }

View File

@ -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&trade; 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;
}
}

View 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&trade; 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);
}
}
}

View File

@ -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;

View File

@ -56,6 +56,7 @@ public @interface PreviewFeature {
public enum Feature { public enum Feature {
PATTERN_MATCHING_IN_INSTANCEOF, PATTERN_MATCHING_IN_INSTANCEOF,
TEXT_BLOCKS, TEXT_BLOCKS,
RECORDS,
; ;
} }
} }

View File

@ -84,6 +84,7 @@ module java.base {
exports java.lang.module; exports java.lang.module;
exports java.lang.ref; exports java.lang.ref;
exports java.lang.reflect; exports java.lang.reflect;
exports java.lang.runtime;
exports java.math; exports java.math;
exports java.net; exports java.net;
exports java.net.spi; exports java.net.spi;
@ -132,9 +133,12 @@ module java.base {
// additional qualified exports may be inserted at build time // additional qualified exports may be inserted at build time
// see make/gensrc/GenModuleInfo.gmk // see make/gensrc/GenModuleInfo.gmk
exports sun.invoke.util to
jdk.compiler;
exports com.sun.security.ntlm to exports com.sun.security.ntlm to
java.security.sasl; java.security.sasl;
exports jdk.internal to exports jdk.internal to
java.compiler,
jdk.jfr, jdk.jfr,
jdk.compiler; jdk.compiler;
exports jdk.internal.access to exports jdk.internal.access to

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -90,7 +90,19 @@ public final class TypeAnnotation {
METHOD_RETURN, METHOD_RETURN,
METHOD_RECEIVER, METHOD_RECEIVER,
METHOD_FORMAL_PARAMETER, 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 { public static final class TypeAnnotationTargetInfo {

View File

@ -38,6 +38,10 @@
#include "check_classname.h" #include "check_classname.h"
#include "java_lang_Class.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 OBJ "Ljava/lang/Object;"
#define CLS "Ljava/lang/Class;" #define CLS "Ljava/lang/Class;"
#define CPL "Ljdk/internal/reflect/ConstantPool;" #define CPL "Ljdk/internal/reflect/ConstantPool;"
@ -73,6 +77,8 @@ static JNINativeMethod methods[] = {
{"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations}, {"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations},
{"getNestHost0", "()" CLS, (void *)&JVM_GetNestHost}, {"getNestHost0", "()" CLS, (void *)&JVM_GetNestHost},
{"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers}, {"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers},
{"getRecordComponents0", "()[" OBJ, (void *)&JVM_GetRecordComponents},
{"isRecord0", "()Z", (void *)&JVM_IsRecord},
}; };
#undef OBJ #undef OBJ

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * The annotation may appear directly or be inherited. Only
* package elements, module elements, and type elements <i>included</i> in this * package elements, module elements, and type elements <i>included</i> in this
* round of annotation processing, or declarations of members, * round of annotation processing, or declarations of members,
* constructors, parameters, or type parameters declared within * constructors, parameters, type parameters, or record components
* those, are returned. Included type elements are {@linkplain * declared within those, are returned. Included type elements are {@linkplain
* #getRootElements root types} and any member types nested within * #getRootElements root types} and any member types nested within
* them. Elements of a package are not considered included simply * them. Elements of a package are not considered included simply
* because a {@code package-info} file for that package was * 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 * The annotation may appear directly or be inherited. Only
* package elements, module elements, and type elements <i>included</i> in this * package elements, module elements, and type elements <i>included</i> in this
* round of annotation processing, or declarations of members, * round of annotation processing, or declarations of members,
* constructors, parameters, or type parameters declared within * constructors, parameters, type parameters, or record components
* those, are returned. Included type elements are {@linkplain * declared within those, are returned. Included type elements are {@linkplain
* #getRootElements root types} and any member types nested within * #getRootElements root types} and any member types nested within
* them. Elements in a package are not considered included simply * them. Elements in a package are not considered included simply
* because a {@code package-info} file for that package was * because a {@code package-info} file for that package was

View File

@ -118,6 +118,7 @@ public interface Element extends javax.lang.model.AnnotatedConstruct {
* @see TypeElement#getSimpleName * @see TypeElement#getSimpleName
* @see VariableElement#getSimpleName * @see VariableElement#getSimpleName
* @see ModuleElement#getSimpleName * @see ModuleElement#getSimpleName
* @see RecordComponentElement#getSimpleName
* @revised 9 * @revised 9
* @spec JPMS * @spec JPMS
*/ */
@ -148,6 +149,11 @@ public interface Element extends javax.lang.model.AnnotatedConstruct {
* parameter}, {@linkplain ExecutableElement the executable * parameter}, {@linkplain ExecutableElement the executable
* element} which declares the parameter is returned. * 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 * <li> If this is a {@linkplain ModuleElement#getEnclosingElement
* module}, {@code null} is returned. * module}, {@code null} is returned.
* *
@ -166,7 +172,7 @@ public interface Element extends javax.lang.model.AnnotatedConstruct {
* *
* A {@linkplain TypeElement#getEnclosedElements class or * A {@linkplain TypeElement#getEnclosedElements class or
* interface} is considered to enclose the fields, methods, * 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} * A {@linkplain PackageElement#getEnclosedElements package}
* encloses the top-level classes and interfaces within it, but is * encloses the top-level classes and interfaces within it, but is

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -46,8 +46,12 @@ public enum ElementKind {
// Declared types // Declared types
/** An enum type. */ /** An enum type. */
ENUM, 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, CLASS,
/** An annotation type. */ /** An annotation type. */
ANNOTATION_TYPE, ANNOTATION_TYPE,
/** /**
@ -90,6 +94,8 @@ public enum ElementKind {
*/ */
OTHER, OTHER,
// Constants added since initial release
/** /**
* A resource variable. * A resource variable.
* @since 1.7 * @since 1.7
@ -101,17 +107,47 @@ public enum ElementKind {
* @since 9 * @since 9
* @spec JPMS * @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: * 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 * @return {@code true} if this is a kind of class
*/ */
@SuppressWarnings("preview")
public boolean isClass() { public boolean isClass() {
return this == CLASS || this == ENUM; return this == CLASS || this == ENUM || this == RECORD;
} }
/** /**

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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) { default R visitModule(ModuleElement e, P p) {
return visitUnknown(e, 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);
}
} }

View File

@ -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();
}

View File

@ -32,7 +32,7 @@ import javax.lang.model.util.*;
/** /**
* Represents a class or interface program element. Provides access * Represents a class or interface program element. Provides access
* to information about the type and its members. Note that an enum * 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. * interface.
* *
* <p> While a {@code TypeElement} represents a class or interface * <p> While a {@code TypeElement} represents a class or interface
@ -82,8 +82,9 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
TypeMirror asType(); TypeMirror asType();
/** /**
* Returns the fields, methods, constructors, and member types * Returns the fields, methods, constructors, record components,
* that are directly declared in this class or interface. * and member types that are directly declared in this class or
* interface.
* *
* This includes any {@linkplain Elements.Origin#MANDATED * This includes any {@linkplain Elements.Origin#MANDATED
* mandated} elements such as the (implicit) default constructor * mandated} elements such as the (implicit) default constructor
@ -177,6 +178,32 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
*/ */
List<? extends TypeParameterElement> getTypeParameters(); 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 * Returns the package of a top-level type and returns the
* immediately lexically enclosing element for a {@linkplain * immediately lexically enclosing element for a {@linkplain

View File

@ -90,8 +90,8 @@
* new RuntimeException();"}. If a program refers to a missing type Xyz, * new RuntimeException();"}. If a program refers to a missing type Xyz,
* the returned model must contain no less information than if the * the returned model must contain no less information than if the
* declaration of type Xyz were assumed to be {@code "class Xyz {}"}, * declaration of type Xyz were assumed to be {@code "class Xyz {}"},
* {@code "interface Xyz {}"}, {@code "enum Xyz {}"}, or {@code * {@code "interface Xyz {}"}, {@code "enum Xyz {}"}, {@code
* "@interface Xyz {}"}. If a program refers to a missing type {@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 * Xyz<K1, ... ,Kn>}, the returned model must contain no less
* information than if the declaration of Xyz were assumed to be * information than if the declaration of Xyz were assumed to be
* {@code "class Xyz<T1, ... ,Tn> {}"} or {@code "interface Xyz<T1, * {@code "class Xyz<T1, ... ,Tn> {}"} or {@code "interface Xyz<T1,

View File

@ -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&trade; 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();
}
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 AbstractAnnotationValueVisitor7
* @see AbstractAnnotationValueVisitor8 * @see AbstractAnnotationValueVisitor8
* @see AbstractAnnotationValueVisitor9 * @see AbstractAnnotationValueVisitor9
* @see AbstractAnnotationValueVisitor14
* @since 1.6 * @since 1.6
*/ */
@SupportedSourceVersion(RELEASE_6) @SupportedSourceVersion(RELEASE_6)

View File

@ -57,6 +57,7 @@ import javax.annotation.processing.SupportedSourceVersion;
* @see AbstractAnnotationValueVisitor6 * @see AbstractAnnotationValueVisitor6
* @see AbstractAnnotationValueVisitor8 * @see AbstractAnnotationValueVisitor8
* @see AbstractAnnotationValueVisitor9 * @see AbstractAnnotationValueVisitor9
* @see AbstractAnnotationValueVisitor14
* @since 1.7 * @since 1.7
*/ */
@SupportedSourceVersion(RELEASE_7) @SupportedSourceVersion(RELEASE_7)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 AbstractAnnotationValueVisitor6
* @see AbstractAnnotationValueVisitor7 * @see AbstractAnnotationValueVisitor7
* @see AbstractAnnotationValueVisitor9 * @see AbstractAnnotationValueVisitor9
* @see AbstractAnnotationValueVisitor14
* @since 1.8 * @since 1.8
*/ */
@SupportedSourceVersion(RELEASE_8) @SupportedSourceVersion(RELEASE_8)

View File

@ -57,6 +57,7 @@ import javax.annotation.processing.SupportedSourceVersion;
* @see AbstractAnnotationValueVisitor6 * @see AbstractAnnotationValueVisitor6
* @see AbstractAnnotationValueVisitor7 * @see AbstractAnnotationValueVisitor7
* @see AbstractAnnotationValueVisitor8 * @see AbstractAnnotationValueVisitor8
* @see AbstractAnnotationValueVisitor14
* @since 9 * @since 9
*/ */
@SupportedSourceVersion(RELEASE_14) @SupportedSourceVersion(RELEASE_14)

View File

@ -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&trade; 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);
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 AbstractElementVisitor7
* @see AbstractElementVisitor8 * @see AbstractElementVisitor8
* @see AbstractElementVisitor9 * @see AbstractElementVisitor9
* @see AbstractElementVisitor14
* @since 1.6 * @since 1.6
*/ */
@SupportedSourceVersion(RELEASE_6) @SupportedSourceVersion(RELEASE_6)
@ -143,4 +144,23 @@ public abstract class AbstractElementVisitor6<R, P> implements ElementVisitor<R,
// Use implementation from interface default method // Use implementation from interface default method
return ElementVisitor.super.visitModule(e, p); 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);
}
} }

View File

@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractElementVisitor6 * @see AbstractElementVisitor6
* @see AbstractElementVisitor8 * @see AbstractElementVisitor8
* @see AbstractElementVisitor9 * @see AbstractElementVisitor9
* @see AbstractElementVisitor14
* @since 1.7 * @since 1.7
*/ */
@SupportedSourceVersion(RELEASE_7) @SupportedSourceVersion(RELEASE_7)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 AbstractElementVisitor6
* @see AbstractElementVisitor7 * @see AbstractElementVisitor7
* @see AbstractElementVisitor9 * @see AbstractElementVisitor9
* @see AbstractElementVisitor14
* @since 1.8 * @since 1.8
*/ */
@SupportedSourceVersion(RELEASE_8) @SupportedSourceVersion(RELEASE_8)

View File

@ -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&trade; 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();
}
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 AbstractTypeVisitor7
* @see AbstractTypeVisitor8 * @see AbstractTypeVisitor8
* @see AbstractTypeVisitor9 * @see AbstractTypeVisitor9
* @see AbstractTypeVisitor14
* @since 1.6 * @since 1.6
*/ */
@SupportedSourceVersion(RELEASE_6) @SupportedSourceVersion(RELEASE_6)

View File

@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractTypeVisitor6 * @see AbstractTypeVisitor6
* @see AbstractTypeVisitor8 * @see AbstractTypeVisitor8
* @see AbstractTypeVisitor9 * @see AbstractTypeVisitor9
* @see AbstractTypeVisitor14
* @since 1.7 * @since 1.7
*/ */
@SupportedSourceVersion(RELEASE_7) @SupportedSourceVersion(RELEASE_7)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 AbstractTypeVisitor6
* @see AbstractTypeVisitor7 * @see AbstractTypeVisitor7
* @see AbstractTypeVisitor9 * @see AbstractTypeVisitor9
* @see AbstractTypeVisitor14
* @since 1.8 * @since 1.8
*/ */
@SupportedSourceVersion(RELEASE_8) @SupportedSourceVersion(RELEASE_8)

View File

@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractTypeVisitor6 * @see AbstractTypeVisitor6
* @see AbstractTypeVisitor7 * @see AbstractTypeVisitor7
* @see AbstractTypeVisitor8 * @see AbstractTypeVisitor8
* @see AbstractTypeVisitor14
* @since 9 * @since 9
*/ */
@SupportedSourceVersion(RELEASE_14) @SupportedSourceVersion(RELEASE_14)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 = private static final Set<ElementKind> MODULE_KIND =
Collections.unmodifiableSet(EnumSet.of(ElementKind.MODULE)); Collections.unmodifiableSet(EnumSet.of(ElementKind.MODULE));
@SuppressWarnings("preview")
private static final Set<ElementKind> TYPE_KINDS = private static final Set<ElementKind> TYPE_KINDS =
Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS, Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS,
ElementKind.ENUM, ElementKind.ENUM,
ElementKind.INTERFACE, ElementKind.INTERFACE,
ElementKind.RECORD,
ElementKind.ANNOTATION_TYPE)); 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}. * Returns a list of fields in {@code elements}.
* @return 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); 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}. * Returns a list of constructors in {@code elements}.
* @return a list of constructors in {@code elements} * @return a list of constructors in {@code elements}

View File

@ -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&trade; 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);
}
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 ElementKindVisitor7
* @see ElementKindVisitor8 * @see ElementKindVisitor8
* @see ElementKindVisitor9 * @see ElementKindVisitor9
* @see ElementKindVisitor14
* @since 1.6 * @since 1.6
*/ */
@SupportedSourceVersion(RELEASE_6) @SupportedSourceVersion(RELEASE_6)
@ -138,6 +139,7 @@ public class ElementKindVisitor6<R, P>
* @param p {@inheritDoc} * @param p {@inheritDoc}
* @return the result of the kind-specific visit method * @return the result of the kind-specific visit method
*/ */
@SuppressWarnings("preview")
@Override @Override
public R visitType(TypeElement e, P p) { public R visitType(TypeElement e, P p) {
ElementKind k = e.getKind(); ElementKind k = e.getKind();
@ -154,6 +156,9 @@ public class ElementKindVisitor6<R, P>
case INTERFACE: case INTERFACE:
return visitTypeAsInterface(e, p); return visitTypeAsInterface(e, p);
case RECORD:
return visitTypeAsRecord(e, p);
default: default:
throw new AssertionError("Bad kind " + k + " for TypeElement" + e); throw new AssertionError("Bad kind " + k + " for TypeElement" + e);
} }
@ -211,6 +216,30 @@ public class ElementKindVisitor6<R, P>
return defaultAction(e, 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 * Visits a variable element
* *

View File

@ -74,6 +74,7 @@ import static javax.lang.model.SourceVersion.*;
* @see ElementKindVisitor6 * @see ElementKindVisitor6
* @see ElementKindVisitor8 * @see ElementKindVisitor8
* @see ElementKindVisitor9 * @see ElementKindVisitor9
* @see ElementKindVisitor14
* @since 1.7 * @since 1.7
*/ */
@SupportedSourceVersion(RELEASE_7) @SupportedSourceVersion(RELEASE_7)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 ElementKindVisitor6
* @see ElementKindVisitor7 * @see ElementKindVisitor7
* @see ElementKindVisitor9 * @see ElementKindVisitor9
* @see ElementKindVisitor14
* @since 1.8 * @since 1.8
*/ */
@SupportedSourceVersion(RELEASE_8) @SupportedSourceVersion(RELEASE_8)

View File

@ -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&trade; 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);
}
}

View File

@ -91,6 +91,7 @@ import static javax.lang.model.SourceVersion.*;
* @see ElementScanner7 * @see ElementScanner7
* @see ElementScanner8 * @see ElementScanner8
* @see ElementScanner9 * @see ElementScanner9
* @see ElementScanner14
* @since 1.6 * @since 1.6
*/ */
@SupportedSourceVersion(RELEASE_6) @SupportedSourceVersion(RELEASE_6)

View File

@ -87,6 +87,7 @@ import static javax.lang.model.SourceVersion.*;
* @see ElementScanner6 * @see ElementScanner6
* @see ElementScanner8 * @see ElementScanner8
* @see ElementScanner9 * @see ElementScanner9
* @see ElementScanner14
* @since 1.7 * @since 1.7
*/ */
@SupportedSourceVersion(RELEASE_7) @SupportedSourceVersion(RELEASE_7)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 ElementScanner6
* @see ElementScanner7 * @see ElementScanner7
* @see ElementScanner9 * @see ElementScanner9
* @see ElementScanner14
* @since 1.8 * @since 1.8
*/ */
@SupportedSourceVersion(RELEASE_8) @SupportedSourceVersion(RELEASE_8)

View File

@ -89,6 +89,7 @@ import static javax.lang.model.SourceVersion.*;
* @see ElementScanner6 * @see ElementScanner6
* @see ElementScanner7 * @see ElementScanner7
* @see ElementScanner8 * @see ElementScanner8
* @see ElementScanner14
* @since 9 * @since 9
* @spec JPMS * @spec JPMS
*/ */

View File

@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Objects;
import javax.lang.model.AnnotatedConstruct; import javax.lang.model.AnnotatedConstruct;
import javax.lang.model.element.*; import javax.lang.model.element.*;
@ -629,4 +630,42 @@ public interface Elements {
* @since 1.8 * @since 1.8
*/ */
boolean isFunctionalInterface(TypeElement type); 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;
}
} }

View File

@ -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&trade; 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);
}
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 SimpleAnnotationValueVisitor7
* @see SimpleAnnotationValueVisitor8 * @see SimpleAnnotationValueVisitor8
* @see SimpleAnnotationValueVisitor9 * @see SimpleAnnotationValueVisitor9
* @see SimpleAnnotationValueVisitor14
* @since 1.6 * @since 1.6
*/ */
@SupportedSourceVersion(RELEASE_6) @SupportedSourceVersion(RELEASE_6)

View File

@ -64,6 +64,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleAnnotationValueVisitor6 * @see SimpleAnnotationValueVisitor6
* @see SimpleAnnotationValueVisitor8 * @see SimpleAnnotationValueVisitor8
* @see SimpleAnnotationValueVisitor9 * @see SimpleAnnotationValueVisitor9
* @see SimpleAnnotationValueVisitor14
* @since 1.7 * @since 1.7
*/ */
@SupportedSourceVersion(RELEASE_7) @SupportedSourceVersion(RELEASE_7)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 SimpleAnnotationValueVisitor6
* @see SimpleAnnotationValueVisitor7 * @see SimpleAnnotationValueVisitor7
* @see SimpleAnnotationValueVisitor8 * @see SimpleAnnotationValueVisitor8
* @see SimpleAnnotationValueVisitor14
* @since 1.8 * @since 1.8
*/ */
@SupportedSourceVersion(RELEASE_8) @SupportedSourceVersion(RELEASE_8)

View File

@ -66,6 +66,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleAnnotationValueVisitor6 * @see SimpleAnnotationValueVisitor6
* @see SimpleAnnotationValueVisitor7 * @see SimpleAnnotationValueVisitor7
* @see SimpleAnnotationValueVisitor8 * @see SimpleAnnotationValueVisitor8
* @see SimpleAnnotationValueVisitor14
* @since 9 * @since 9
*/ */
@SupportedSourceVersion(RELEASE_14) @SupportedSourceVersion(RELEASE_14)

View File

@ -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&trade; 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);
}
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 SimpleElementVisitor7
* @see SimpleElementVisitor8 * @see SimpleElementVisitor8
* @see SimpleElementVisitor9 * @see SimpleElementVisitor9
* @see SimpleElementVisitor14
* @since 1.6 * @since 1.6
*/ */
@SupportedSourceVersion(RELEASE_6) @SupportedSourceVersion(RELEASE_6)

View File

@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleElementVisitor6 * @see SimpleElementVisitor6
* @see SimpleElementVisitor8 * @see SimpleElementVisitor8
* @see SimpleElementVisitor9 * @see SimpleElementVisitor9
* @see SimpleElementVisitor14
* @since 1.7 * @since 1.7
*/ */
@SupportedSourceVersion(RELEASE_7) @SupportedSourceVersion(RELEASE_7)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 SimpleElementVisitor6
* @see SimpleElementVisitor7 * @see SimpleElementVisitor7
* @see SimpleElementVisitor9 * @see SimpleElementVisitor9
* @see SimpleElementVisitor14
* @since 1.8 * @since 1.8
*/ */
@SupportedSourceVersion(RELEASE_8) @SupportedSourceVersion(RELEASE_8)

View File

@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleElementVisitor6 * @see SimpleElementVisitor6
* @see SimpleElementVisitor7 * @see SimpleElementVisitor7
* @see SimpleElementVisitor8 * @see SimpleElementVisitor8
* @see SimpleElementVisitor14
* @since 9 * @since 9
* @spec JPMS * @spec JPMS
*/ */

View File

@ -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&trade; 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);
}
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 SimpleTypeVisitor7
* @see SimpleTypeVisitor8 * @see SimpleTypeVisitor8
* @see SimpleTypeVisitor9 * @see SimpleTypeVisitor9
* @see SimpleTypeVisitor14
* @since 1.6 * @since 1.6
*/ */
@SupportedSourceVersion(RELEASE_6) @SupportedSourceVersion(RELEASE_6)

View File

@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleTypeVisitor6 * @see SimpleTypeVisitor6
* @see SimpleTypeVisitor8 * @see SimpleTypeVisitor8
* @see SimpleTypeVisitor9 * @see SimpleTypeVisitor9
* @see SimpleTypeVisitor14
* @since 1.7 * @since 1.7
*/ */
@SupportedSourceVersion(RELEASE_7) @SupportedSourceVersion(RELEASE_7)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 SimpleTypeVisitor6
* @see SimpleTypeVisitor7 * @see SimpleTypeVisitor7
* @see SimpleTypeVisitor9 * @see SimpleTypeVisitor9
* @see SimpleTypeVisitor14
* @since 1.8 * @since 1.8
*/ */
@SupportedSourceVersion(RELEASE_8) @SupportedSourceVersion(RELEASE_8)

View File

@ -71,6 +71,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleTypeVisitor6 * @see SimpleTypeVisitor6
* @see SimpleTypeVisitor7 * @see SimpleTypeVisitor7
* @see SimpleTypeVisitor8 * @see SimpleTypeVisitor8
* @see SimpleTypeVisitor14
* @since 9 * @since 9
*/ */
@SupportedSourceVersion(RELEASE_14) @SupportedSourceVersion(RELEASE_14)

View File

@ -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&trade; 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);
}
}

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 TypeKindVisitor7
* @see TypeKindVisitor8 * @see TypeKindVisitor8
* @see TypeKindVisitor9
* @see TypeKindVisitor14
* @since 1.6 * @since 1.6
*/ */
@SupportedSourceVersion(RELEASE_6) @SupportedSourceVersion(RELEASE_6)

View File

@ -71,6 +71,8 @@ import javax.lang.model.SourceVersion;
* *
* @see TypeKindVisitor6 * @see TypeKindVisitor6
* @see TypeKindVisitor8 * @see TypeKindVisitor8
* @see TypeKindVisitor9
* @see TypeKindVisitor14
* @since 1.7 * @since 1.7
*/ */
@SupportedSourceVersion(RELEASE_7) @SupportedSourceVersion(RELEASE_7)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 TypeKindVisitor6
* @see TypeKindVisitor7 * @see TypeKindVisitor7
* @see TypeKindVisitor9
* @see TypeKindVisitor14
* @since 1.8 * @since 1.8
*/ */
@SupportedSourceVersion(RELEASE_8) @SupportedSourceVersion(RELEASE_8)

View File

@ -75,6 +75,7 @@ import static javax.lang.model.SourceVersion.*;
* @see TypeKindVisitor6 * @see TypeKindVisitor6
* @see TypeKindVisitor7 * @see TypeKindVisitor7
* @see TypeKindVisitor8 * @see TypeKindVisitor8
* @see TypeKindVisitor14
* @since 9 * @since 9
*/ */
@SupportedSourceVersion(RELEASE_14) @SupportedSourceVersion(RELEASE_14)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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: case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED:
throwableClassName = "java/lang/UnsupportedOperationException"; 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; break;
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED: case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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; 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. * type declaration.
* *
* For example: * For example:
@ -44,6 +44,7 @@ import javax.lang.model.element.Name;
* *
* @jls 8.1 Class Declarations * @jls 8.1 Class Declarations
* @jls 8.9 Enum Types * @jls 8.9 Enum Types
* @jls 8.10 Record Types
* @jls 9.1 Interface Declarations * @jls 9.1 Interface Declarations
* @jls 9.6 Annotation Types * @jls 9.6 Annotation Types
* *

View File

@ -648,6 +648,22 @@ public interface Tree {
*/ */
PROVIDES(ProvidesTree.class), 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 * Used for instances of {@link RequiresTree} representing
* requires directives in a module declaration. * requires directives in a module declaration.

View File

@ -203,6 +203,7 @@ public class Checker extends DocTreePathScanner<Void, Void> {
case INTERFACE: case INTERFACE:
case ENUM: case ENUM:
case ANNOTATION_TYPE: case ANNOTATION_TYPE:
case RECORD:
implicitHeadingRank = 1; implicitHeadingRank = 1;
break; break;

View File

@ -420,10 +420,10 @@ public class JavacTrees extends DocTrees {
@Override @DefinedBy(Api.COMPILER_TREE) @Override @DefinedBy(Api.COMPILER_TREE)
public Element getElement(DocTreePath path) { public Element getElement(DocTreePath path) {
DocTree forTree = path.getLeaf(); DocTree tree = path.getLeaf();
if (forTree instanceof DCReference) if (tree instanceof DCReference)
return attributeDocReference(path.getTreePath(), ((DCReference) forTree)); return attributeDocReference(path.getTreePath(), ((DCReference) tree));
if (forTree instanceof DCIdentifier) { if (tree instanceof DCIdentifier) {
if (path.getParentPath().getLeaf() instanceof DCParam) { if (path.getParentPath().getLeaf() instanceof DCParam) {
return attributeParamIdentifier(path.getTreePath(), (DCParam) path.getParentPath().getLeaf()); 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); Symbol javadocSymbol = getElement(path);
if (javadocSymbol == null) if (javadocSymbol == null)
return null; return null;
@ -544,16 +544,18 @@ public class JavacTrees extends DocTrees {
List<? extends Symbol> params = List.nil(); List<? extends Symbol> params = List.nil();
if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) { if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) {
MethodSymbol ee = (MethodSymbol) javadocSymbol; MethodSymbol ee = (MethodSymbol) javadocSymbol;
params = ptag.isTypeParameter() params = paramTag.isTypeParameter()
? ee.getTypeParameters() ? ee.getTypeParameters()
: ee.getParameters(); : ee.getParameters();
} else if (kind.isClass() || kind.isInterface()) { } else if (kind.isClass() || kind.isInterface()) {
ClassSymbol te = (ClassSymbol) javadocSymbol; ClassSymbol te = (ClassSymbol) javadocSymbol;
params = te.getTypeParameters(); params = paramTag.isTypeParameter()
? te.getTypeParameters()
: te.getRecordComponents();
} }
for (Symbol param : params) { for (Symbol param : params) {
if (param.getSimpleName() == ptag.getName().getName()) { if (param.getSimpleName() == paramTag.getName().getName()) {
return param; return param;
} }
} }

View File

@ -344,12 +344,35 @@ public class Flags {
*/ */
public static final long MATCH_BINDING_TO_OUTER = 1L<<60; 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. /** Modifier masks.
*/ */
public static final int public static final int
AccessFlags = PUBLIC | PROTECTED | PRIVATE, AccessFlags = PUBLIC | PROTECTED | PRIVATE,
LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC, LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
LocalRecordFlags = LocalClassFlags | STATIC,
MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags, MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags,
MemberRecordFlags = MemberClassFlags | STATIC,
ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION, ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
InterfaceVarFlags = FINAL | STATIC | PUBLIC, InterfaceVarFlags = FINAL | STATIC | PUBLIC,
VarFlags = AccessFlags | FINAL | STATIC | VarFlags = AccessFlags | FINAL | STATIC |
@ -357,6 +380,8 @@ public class Flags {
ConstructorFlags = AccessFlags, ConstructorFlags = AccessFlags,
InterfaceMethodFlags = ABSTRACT | PUBLIC, InterfaceMethodFlags = ABSTRACT | PUBLIC,
MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE | MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE |
SYNCHRONIZED | FINAL | STRICTFP,
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
SYNCHRONIZED | FINAL | STRICTFP; SYNCHRONIZED | FINAL | STRICTFP;
public static final long public static final long
ExtendedStandardFlags = (long)StandardFlags | DEFAULT, ExtendedStandardFlags = (long)StandardFlags | DEFAULT,
@ -465,7 +490,8 @@ public class Flags {
PREVIEW_API(Flags.PREVIEW_API), PREVIEW_API(Flags.PREVIEW_API),
PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API), PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API),
MATCH_BINDING(Flags.MATCH_BINDING), 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) { Flag(long flag) {
this.value = flag; this.value = flag;

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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"), STATIC_INIT("kindname.static.init"),
INSTANCE_INIT("kindname.instance.init"), INSTANCE_INIT("kindname.instance.init"),
PACKAGE("kindname.package"), PACKAGE("kindname.package"),
MODULE("kindname.module"); MODULE("kindname.module"),
RECORD_COMPONENT("kindname.record.component"),
RECORD("kindname.record");
private final String name; private final String name;
@ -279,6 +281,9 @@ public class Kinds {
case CLASS: case CLASS:
return KindName.CLASS; return KindName.CLASS;
case RECORD:
return KindName.RECORD;
case INTERFACE: case INTERFACE:
return KindName.INTERFACE; return KindName.INTERFACE;
@ -286,13 +291,15 @@ public class Kinds {
return KindName.TYPEVAR; return KindName.TYPEVAR;
case ENUM_CONSTANT: case ENUM_CONSTANT:
case FIELD:
case PARAMETER: case PARAMETER:
case LOCAL_VARIABLE: case LOCAL_VARIABLE:
case EXCEPTION_PARAMETER: case EXCEPTION_PARAMETER:
case RESOURCE_VARIABLE: case RESOURCE_VARIABLE:
return KindName.VAR; return KindName.VAR;
case FIELD:
return ((sym.flags_field & RECORD) != 0) ? KindName.RECORD_COMPONENT : KindName.VAR;
case CONSTRUCTOR: case CONSTRUCTOR:
return KindName.CONSTRUCTOR; return KindName.CONSTRUCTOR;

View File

@ -167,7 +167,8 @@ public class Preview {
public boolean isPreview(Feature feature) { public boolean isPreview(Feature feature) {
if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF || if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF ||
feature == Feature.REIFIABLE_TYPES_INSTANCEOF || feature == Feature.REIFIABLE_TYPES_INSTANCEOF ||
feature == Feature.TEXT_BLOCKS) feature == Feature.TEXT_BLOCKS ||
feature == Feature.RECORDS)
return true; return true;
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing). //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' //When real preview features will be added, this method can be implemented to return 'true'

View File

@ -201,6 +201,7 @@ public enum Source {
TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL), TEXT_BLOCKS(JDK14, Fragments.FeatureTextBlocks, DiagKind.PLURAL),
PATTERN_MATCHING_IN_INSTANCEOF(JDK14, Fragments.FeaturePatternMatchingInstanceof, DiagKind.NORMAL), PATTERN_MATCHING_IN_INSTANCEOF(JDK14, Fragments.FeaturePatternMatchingInstanceof, DiagKind.NORMAL),
REIFIABLE_TYPES_INSTANCEOF(JDK14, Fragments.FeatureReifiableTypesInstanceof, DiagKind.PLURAL), REIFIABLE_TYPES_INSTANCEOF(JDK14, Fragments.FeatureReifiableTypesInstanceof, DiagKind.PLURAL),
RECORDS(JDK14, Fragments.FeatureRecords, DiagKind.PLURAL),
; ;
enum DiagKind { enum DiagKind {

View File

@ -42,6 +42,7 @@ import javax.lang.model.element.Modifier;
import javax.lang.model.element.ModuleElement; import javax.lang.model.element.ModuleElement;
import javax.lang.model.element.NestingKind; import javax.lang.model.element.NestingKind;
import javax.lang.model.element.PackageElement; import javax.lang.model.element.PackageElement;
import javax.lang.model.element.RecordComponentElement;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement; 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.tree.JCTree.Tag;
import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.DefinedBy.Api; import com.sun.tools.javac.util.DefinedBy.Api;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Name;
import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Flags.*;
import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.Kinds.*;
import static com.sun.tools.javac.code.Kinds.Kind.*; 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 static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
import com.sun.tools.javac.code.Scope.WriteableScope; 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.CLASS;
import static com.sun.tools.javac.code.TypeTag.FORALL; import static com.sun.tools.javac.code.TypeTag.FORALL;
import static com.sun.tools.javac.code.TypeTag.TYPEVAR; 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.lushrl;
import static com.sun.tools.javac.jvm.ByteCodes.lxor; import static com.sun.tools.javac.jvm.ByteCodes.lxor;
import static com.sun.tools.javac.jvm.ByteCodes.string_add; 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 /** Root class for Java symbols. It contains subclasses
* for specific sorts of symbols, such as variables, methods and operators, * for specific sorts of symbols, such as variables, methods and operators,
@ -406,14 +403,26 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
return (flags() & INTERFACE) != 0; return (flags() & INTERFACE) != 0;
} }
public boolean isAbstract() {
return (flags_field & ABSTRACT) != 0;
}
public boolean isPrivate() { public boolean isPrivate() {
return (flags_field & Flags.AccessFlags) == PRIVATE; return (flags_field & Flags.AccessFlags) == PRIVATE;
} }
public boolean isPublic() {
return (flags_field & Flags.AccessFlags) == PUBLIC;
}
public boolean isEnum() { public boolean isEnum() {
return (flags() & ENUM) != 0; return (flags() & ENUM) != 0;
} }
public boolean isFinal() {
return (flags_field & FINAL) != 0;
}
/** Is this symbol declared (directly or indirectly) local /** Is this symbol declared (directly or indirectly) local
* to a method or variable initializer? * to a method or variable initializer?
* Also includes fields of inner classes which are in * Also includes fields of inner classes which are in
@ -828,7 +837,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
} }
@Override @DefinedBy(Api.LANGUAGE_MODEL) @Override @DefinedBy(Api.LANGUAGE_MODEL)
public java.util.List<Symbol> getEnclosedElements() { public List<Symbol> getEnclosedElements() {
List<Symbol> list = List.nil(); List<Symbol> list = List.nil();
if (kind == TYP && type.hasTag(TYPEVAR)) { if (kind == TYP && type.hasTag(TYPEVAR)) {
return list; return list;
@ -1264,6 +1273,8 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
/** the annotation metadata attached to this class */ /** the annotation metadata attached to this class */
private AnnotationTypeMetadata annotationTypeMetadata; private AnnotationTypeMetadata annotationTypeMetadata;
private List<RecordComponent> recordComponents = List.nil();
public ClassSymbol(long flags, Name name, Type type, Symbol owner) { public ClassSymbol(long flags, Name name, Type type, Symbol owner) {
super(TYP, flags, name, type, owner); super(TYP, flags, name, type, owner);
this.members_field = null; this.members_field = null;
@ -1332,6 +1343,18 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
return fullname; 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() { public Name flatName() {
return flatname; return flatname;
} }
@ -1424,6 +1447,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
@DefinedBy(Api.LANGUAGE_MODEL) @DefinedBy(Api.LANGUAGE_MODEL)
@SuppressWarnings("preview")
public ElementKind getKind() { public ElementKind getKind() {
apiComplete(); apiComplete();
long flags = flags(); long flags = flags();
@ -1433,6 +1457,8 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
return ElementKind.INTERFACE; return ElementKind.INTERFACE;
else if ((flags & ENUM) != 0) else if ((flags & ENUM) != 0)
return ElementKind.ENUM; return ElementKind.ENUM;
else if ((flags & RECORD) != 0)
return ElementKind.RECORD;
else else
return ElementKind.CLASS; return ElementKind.CLASS;
} }
@ -1444,6 +1470,25 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
return Flags.asModifierSet(flags & ~DEFAULT); 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) @DefinedBy(Api.LANGUAGE_MODEL)
public NestingKind getNestingKind() { public NestingKind getNestingKind() {
apiComplete(); apiComplete();
@ -1457,7 +1502,6 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
return NestingKind.MEMBER; return NestingKind.MEMBER;
} }
@Override @Override
protected <A extends Annotation> Attribute.Compound getAttribute(final Class<A> annoType) { 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); : superType.getAttribute(annoType);
} }
@DefinedBy(Api.LANGUAGE_MODEL) @DefinedBy(Api.LANGUAGE_MODEL)
public <R, P> R accept(ElementVisitor<R, P> v, P p) { public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitType(this, p); return v.visitType(this, p);
@ -1534,6 +1575,10 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
Assert.check(!annotationTypeMetadata.isMetadataForAnnotationType()); Assert.check(!annotationTypeMetadata.isMetadataForAnnotationType());
this.annotationTypeMetadata = a; 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 static class ParamSymbol extends VarSymbol {
public ParamSymbol(long flags, Name name, Type type, Symbol owner) { public ParamSymbol(long flags, Name name, Type type, Symbol owner) {
super(flags, name, type, owner); super(flags, name, type, owner);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -255,4 +255,36 @@ public class SymbolMetadata {
private boolean isStarted() { private boolean isStarted() {
return attributes != DECL_NOT_STARTED; 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);
}
}
} }

View File

@ -161,6 +161,7 @@ public class Symtab {
/** Predefined types. /** Predefined types.
*/ */
public final Type objectType; public final Type objectType;
public final Type objectMethodsType;
public final Type objectsType; public final Type objectsType;
public final Type classType; public final Type classType;
public final Type classLoaderType; public final Type classLoaderType;
@ -215,6 +216,8 @@ public class Symtab {
public final Type elementTypeType; public final Type elementTypeType;
public final Type functionalInterfaceType; public final Type functionalInterfaceType;
public final Type previewFeatureType; public final Type previewFeatureType;
public final Type typeDescriptorType;
public final Type recordType;
/** The symbol representing the length field of an array. /** 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. // Enter predefined classes. All are assumed to be in the java.base module.
objectType = enterClass("java.lang.Object"); objectType = enterClass("java.lang.Object");
objectMethodsType = enterClass("java.lang.runtime.ObjectMethods");
objectsType = enterClass("java.util.Objects"); objectsType = enterClass("java.util.Objects");
classType = enterClass("java.lang.Class"); classType = enterClass("java.lang.Class");
stringType = enterClass("java.lang.String"); stringType = enterClass("java.lang.String");
@ -572,6 +576,8 @@ public class Symtab {
stringConcatFactory = enterClass("java.lang.invoke.StringConcatFactory"); stringConcatFactory = enterClass("java.lang.invoke.StringConcatFactory");
functionalInterfaceType = enterClass("java.lang.FunctionalInterface"); functionalInterfaceType = enterClass("java.lang.FunctionalInterface");
previewFeatureType = enterClass("jdk.internal.PreviewFeature"); previewFeatureType = enterClass("jdk.internal.PreviewFeature");
typeDescriptorType = enterClass("java.lang.invoke.TypeDescriptor");
recordType = enterClass("java.lang.Record");
synthesizeEmptyInterfaceIfMissing(autoCloseableType); synthesizeEmptyInterfaceIfMissing(autoCloseableType);
synthesizeEmptyInterfaceIfMissing(cloneableType); synthesizeEmptyInterfaceIfMissing(cloneableType);

Some files were not shown because too many files have changed in this diff Show More