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.
#
# This code is free software; you can redistribute it and/or modify it
@ -80,6 +80,7 @@ define SetupInterimModule
ADD_JAVAC_FLAGS := --module-path $(BUILDTOOLS_OUTPUTDIR)/interim_langtools_modules \
$$(INTERIM_LANGTOOLS_ADD_EXPORTS) \
--patch-module java.base=$(BUILDTOOLS_OUTPUTDIR)/gensrc/java.base.interim \
--add-exports java.base/jdk.internal=java.compiler.interim \
--add-exports java.base/jdk.internal=jdk.compiler.interim \
-Xlint:-module, \
))

View File

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

View File

@ -55,6 +55,7 @@
#include "oops/metadata.hpp"
#include "oops/method.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/recordComponent.hpp"
#include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp"
@ -3211,6 +3212,173 @@ u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream
return length;
}
// Record {
// u2 attribute_name_index;
// u4 attribute_length;
// u2 components_count;
// component_info components[components_count];
// }
// component_info {
// u2 name_index;
// u2 descriptor_index
// u2 attributes_count;
// attribute_info_attributes[attributes_count];
// }
u2 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* const cfs,
const ConstantPool* cp,
const u1* const record_attribute_start,
TRAPS) {
const u1* const current_mark = cfs->current();
int components_count = 0;
unsigned int calculate_attr_size = 0;
if (record_attribute_start != NULL) {
cfs->set_current(record_attribute_start);
cfs->guarantee_more(2, CHECK_0); // num of components
components_count = (int)cfs->get_u2_fast();
calculate_attr_size = 2;
}
Array<RecordComponent*>* const record_components =
MetadataFactory::new_array<RecordComponent*>(_loader_data, components_count, NULL, CHECK_0);
_record_components = record_components;
for (int x = 0; x < components_count; x++) {
cfs->guarantee_more(6, CHECK_0); // name_index, descriptor_index, attributes_count
const u2 name_index = cfs->get_u2_fast();
check_property(valid_symbol_at(name_index),
"Invalid constant pool index %u for name in Record attribute in class file %s",
name_index, CHECK_0);
const Symbol* const name = cp->symbol_at(name_index);
verify_legal_field_name(name, CHECK_0);
const u2 descriptor_index = cfs->get_u2_fast();
check_property(valid_symbol_at(descriptor_index),
"Invalid constant pool index %u for descriptor in Record attribute in class file %s",
descriptor_index, CHECK_0);
const Symbol* const descr = cp->symbol_at(descriptor_index);
verify_legal_field_signature(name, descr, CHECK_0);
const u2 attributes_count = cfs->get_u2_fast();
calculate_attr_size += 6;
u2 generic_sig_index = 0;
const u1* runtime_visible_annotations = NULL;
int runtime_visible_annotations_length = 0;
const u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
bool runtime_invisible_annotations_exists = false;
const u1* runtime_visible_type_annotations = NULL;
int runtime_visible_type_annotations_length = 0;
const u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_type_annotations_exists = false;
// Expected attributes for record components are Signature, Runtime(In)VisibleAnnotations,
// and Runtime(In)VisibleTypeAnnotations. Other attributes are ignored.
for (int y = 0; y < attributes_count; y++) {
cfs->guarantee_more(6, CHECK_0); // attribute_name_index, attribute_length
const u2 attribute_name_index = cfs->get_u2_fast();
const u4 attribute_length = cfs->get_u4_fast();
calculate_attr_size += 6;
check_property(
valid_symbol_at(attribute_name_index),
"Invalid Record attribute name index %u in class file %s",
attribute_name_index, CHECK_0);
const Symbol* const attribute_name = cp->symbol_at(attribute_name_index);
if (attribute_name == vmSymbols::tag_signature()) {
if (generic_sig_index != 0) {
classfile_parse_error(
"Multiple Signature attributes for Record component in class file %s",
CHECK_0);
}
if (attribute_length != 2) {
classfile_parse_error(
"Invalid Signature attribute length %u in Record component in class file %s",
attribute_length, CHECK_0);
}
generic_sig_index = parse_generic_signature_attribute(cfs, CHECK_0);
} else if (attribute_name == vmSymbols::tag_runtime_visible_annotations()) {
if (runtime_visible_annotations != NULL) {
classfile_parse_error(
"Multiple RuntimeVisibleAnnotations attributes for Record component in class file %s", CHECK_0);
}
runtime_visible_annotations_length = attribute_length;
runtime_visible_annotations = cfs->current();
assert(runtime_visible_annotations != NULL, "null record component visible annotation");
cfs->guarantee_more(runtime_visible_annotations_length, CHECK_0);
cfs->skip_u1_fast(runtime_visible_annotations_length);
} else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
classfile_parse_error(
"Multiple RuntimeInvisibleAnnotations attributes for Record component in class file %s", CHECK_0);
}
runtime_invisible_annotations_exists = true;
if (PreserveAllAnnotations) {
runtime_invisible_annotations_length = attribute_length;
runtime_invisible_annotations = cfs->current();
assert(runtime_invisible_annotations != NULL, "null record component invisible annotation");
}
cfs->skip_u1(attribute_length, CHECK_0);
} else if (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
if (runtime_visible_type_annotations != NULL) {
classfile_parse_error(
"Multiple RuntimeVisibleTypeAnnotations attributes for Record component in class file %s", CHECK_0);
}
runtime_visible_type_annotations_length = attribute_length;
runtime_visible_type_annotations = cfs->current();
assert(runtime_visible_type_annotations != NULL, "null record component visible type annotation");
cfs->guarantee_more(runtime_visible_type_annotations_length, CHECK_0);
cfs->skip_u1_fast(runtime_visible_type_annotations_length);
} else if (attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
if (runtime_invisible_type_annotations_exists) {
classfile_parse_error(
"Multiple RuntimeInvisibleTypeAnnotations attributes for Record component in class file %s", CHECK_0);
}
runtime_invisible_type_annotations_exists = true;
if (PreserveAllAnnotations) {
runtime_invisible_type_annotations_length = attribute_length;
runtime_invisible_type_annotations = cfs->current();
assert(runtime_invisible_type_annotations != NULL, "null record component invisible type annotation");
}
cfs->skip_u1(attribute_length, CHECK_0);
} else {
// Skip unknown attributes
cfs->skip_u1(attribute_length, CHECK_0);
}
calculate_attr_size += attribute_length;
} // End of attributes For loop
AnnotationArray* annotations = assemble_annotations(runtime_visible_annotations,
runtime_visible_annotations_length,
runtime_invisible_annotations,
runtime_invisible_annotations_length,
CHECK_0);
AnnotationArray* type_annotations = assemble_annotations(runtime_visible_type_annotations,
runtime_visible_type_annotations_length,
runtime_invisible_type_annotations,
runtime_invisible_type_annotations_length,
CHECK_0);
RecordComponent* record_component =
RecordComponent::allocate(_loader_data, name_index, descriptor_index,
attributes_count, generic_sig_index,
annotations, type_annotations, CHECK_0);
record_components->at_put(x, record_component);
} // End of component processing loop
// Restore buffer's current position.
cfs->set_current(current_mark);
return calculate_attr_size;
}
void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) {
set_class_synthetic_flag(true);
}
@ -3308,6 +3476,12 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil
CHECK);
}
bool ClassFileParser::supports_records() {
return _major_version == JAVA_14_VERSION &&
_minor_version == JAVA_PREVIEW_MINOR_VERSION &&
Arguments::enable_preview();
}
void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
ConstantPool* cp,
ClassFileParser::ClassAnnotationCollector* parsed_annotations,
@ -3326,6 +3500,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
bool parsed_innerclasses_attribute = false;
bool parsed_nest_members_attribute = false;
bool parsed_nest_host_attribute = false;
bool parsed_record_attribute = false;
bool parsed_enclosingmethod_attribute = false;
bool parsed_bootstrap_methods_attribute = false;
const u1* runtime_visible_annotations = NULL;
@ -3345,6 +3520,8 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
u2 enclosing_method_method_index = 0;
const u1* nest_members_attribute_start = NULL;
u4 nest_members_attribute_length = 0;
const u1* record_attribute_start = NULL;
u4 record_attribute_length = 0;
// Iterate over attributes
while (attributes_count--) {
@ -3527,6 +3704,38 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
"Nest-host class_info_index %u has bad constant type in class file %s",
class_info_index, CHECK);
_nest_host = class_info_index;
} else if (_major_version >= JAVA_14_VERSION) {
if (tag == vmSymbols::tag_record()) {
// Skip over Record attribute if not supported or if super class is
// not java.lang.Record.
if (supports_records() &&
cp->klass_name_at(_super_class_index) == vmSymbols::java_lang_Record()) {
if (parsed_record_attribute) {
classfile_parse_error("Multiple Record attributes in class file %s", CHECK);
}
// Check that class is final and not abstract.
if (!_access_flags.is_final() || _access_flags.is_abstract()) {
classfile_parse_error("Record attribute in non-final or abstract class file %s", CHECK);
}
parsed_record_attribute = true;
record_attribute_start = cfs->current();
record_attribute_length = attribute_length;
} else if (log_is_enabled(Info, class, record)) {
// Log why the Record attribute was ignored. Note that if the
// class file version is 58.65535 and --enable-preview wasn't
// specified then a java.lang.UnsupportedClassVersionError
// exception would have been thrown.
ResourceMark rm(THREAD);
log_info(class, record)("Ignoring Record attribute in class %s because %s",
_class_name->as_C_string(),
supports_records() ? "super type is not java.lang.Record" :
"class file version is not 58.65535");
}
cfs->skip_u1(attribute_length, CHECK);
} else {
// Unknown attribute
cfs->skip_u1(attribute_length, CHECK);
}
} else {
// Unknown attribute
cfs->skip_u1(attribute_length, CHECK);
@ -3578,6 +3787,19 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
}
}
if (parsed_record_attribute) {
const unsigned int calculated_attr_length = parse_classfile_record_attribute(
cfs,
cp,
record_attribute_start,
CHECK);
if (_need_verify) {
guarantee_property(record_attribute_length == calculated_attr_length,
"Record attribute has wrong length in class file %s",
CHECK);
}
}
if (_max_bootstrap_specifier_index >= 0) {
guarantee_property(parsed_bootstrap_methods_attribute,
"Missing BootstrapMethods attribute in class file %s", CHECK);
@ -3632,7 +3854,8 @@ void ClassFileParser::create_combined_annotations(TRAPS) {
// Transfer ownership of metadata allocated to the InstanceKlass.
void ClassFileParser::apply_parsed_class_metadata(
InstanceKlass* this_klass,
int java_fields_count, TRAPS) {
int java_fields_count,
TRAPS) {
assert(this_klass != NULL, "invariant");
_cp->set_pool_holder(this_klass);
@ -3644,6 +3867,7 @@ void ClassFileParser::apply_parsed_class_metadata(
this_klass->set_nest_host_index(_nest_host);
this_klass->set_local_interfaces(_local_interfaces);
this_klass->set_annotations(_combined_annotations);
this_klass->set_record_components(_record_components);
// Delay the setting of _transitive_interfaces until after initialize_supers() in
// fill_instance_klass(). It is because the _transitive_interfaces may be shared with
// its _super. If an OOM occurs while loading the current klass, its _super field
@ -4514,6 +4738,7 @@ static Array<InstanceKlass*>* compute_transitive_interfaces(const InstanceKlass*
static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
assert(this_klass != NULL, "invariant");
const Klass* const super = this_klass->super();
if (super != NULL) {
// If the loader is not the boot loader then throw an exception if its
@ -4715,12 +4940,13 @@ void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const {
const bool is_super = (flags & JVM_ACC_SUPER) != 0;
const bool is_enum = (flags & JVM_ACC_ENUM) != 0;
const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0;
const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION;
const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION;
const bool major_gte_14 = _major_version >= JAVA_14_VERSION;
if ((is_abstract && is_final) ||
(is_interface && !is_abstract) ||
(is_interface && major_gte_15 && (is_super || is_enum)) ||
(!is_interface && major_gte_15 && is_annotation)) {
(is_interface && major_gte_1_5 && (is_super || is_enum)) ||
(!is_interface && major_gte_1_5 && is_annotation)) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
@ -4816,14 +5042,14 @@ void ClassFileParser::verify_legal_field_modifiers(jint flags,
const bool is_volatile = (flags & JVM_ACC_VOLATILE) != 0;
const bool is_transient = (flags & JVM_ACC_TRANSIENT) != 0;
const bool is_enum = (flags & JVM_ACC_ENUM) != 0;
const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION;
const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION;
bool is_illegal = false;
if (is_interface) {
if (!is_public || !is_static || !is_final || is_private ||
is_protected || is_volatile || is_transient ||
(major_gte_15 && is_enum)) {
(major_gte_1_5 && is_enum)) {
is_illegal = true;
}
} else { // not interface
@ -4859,7 +5085,7 @@ void ClassFileParser::verify_legal_method_modifiers(jint flags,
const bool is_strict = (flags & JVM_ACC_STRICT) != 0;
const bool is_synchronized = (flags & JVM_ACC_SYNCHRONIZED) != 0;
const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0;
const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION;
const bool major_gte_1_5 = _major_version >= JAVA_1_5_VERSION;
const bool major_gte_8 = _major_version >= JAVA_8_VERSION;
const bool is_initializer = (name == vmSymbols::object_initializer_name());
@ -4882,7 +5108,7 @@ void ClassFileParser::verify_legal_method_modifiers(jint flags,
(is_abstract && (is_private || is_static || is_strict))) {
is_illegal = true;
}
} else if (major_gte_15) {
} else if (major_gte_1_5) {
// Class file version in the interval [JAVA_1_5_VERSION, JAVA_8_VERSION)
if (!is_public || is_private || is_protected || is_static || is_final ||
is_synchronized || is_native || !is_abstract || is_strict) {
@ -4900,13 +5126,13 @@ void ClassFileParser::verify_legal_method_modifiers(jint flags,
} else {
if (is_initializer) {
if (is_static || is_final || is_synchronized || is_native ||
is_abstract || (major_gte_15 && is_bridge)) {
is_abstract || (major_gte_1_5 && is_bridge)) {
is_illegal = true;
}
} else { // not initializer
if (is_abstract) {
if ((is_final || is_native || is_private || is_static ||
(major_gte_15 && (is_synchronized || is_strict)))) {
(major_gte_1_5 && (is_synchronized || is_strict)))) {
is_illegal = true;
}
}
@ -5495,6 +5721,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
assert(NULL == _nest_members, "invariant");
assert(NULL == _local_interfaces, "invariant");
assert(NULL == _combined_annotations, "invariant");
assert(NULL == _record_components, "invariant");
if (_has_final_method) {
ik->set_has_final_method();
@ -5776,6 +6003,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_inner_classes(NULL),
_nest_members(NULL),
_nest_host(0),
_record_components(NULL),
_local_interfaces(NULL),
_transitive_interfaces(NULL),
_combined_annotations(NULL),
@ -5886,6 +6114,7 @@ void ClassFileParser::clear_class_metadata() {
_combined_annotations = NULL;
_class_annotations = _class_type_annotations = NULL;
_fields_annotations = _fields_type_annotations = NULL;
_record_components = NULL;
}
// Destructor to clean up
@ -5913,6 +6142,10 @@ ClassFileParser::~ClassFileParser() {
MetadataFactory::free_array<u2>(_loader_data, _nest_members);
}
if (_record_components != NULL) {
InstanceKlass::deallocate_record_components(_loader_data, _record_components);
}
// Free interfaces
InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
_local_interfaces, _transitive_interfaces);

View File

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

View File

@ -50,6 +50,7 @@
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "oops/recordComponent.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/resolvedMethodTable.hpp"
@ -3148,6 +3149,64 @@ void java_lang_reflect_Field::set_annotations(oop field, oop value) {
field->obj_field_put(annotations_offset, value);
}
oop java_lang_reflect_RecordComponent::create(InstanceKlass* holder, RecordComponent* component, TRAPS) {
// Allocate java.lang.reflect.RecordComponent instance
HandleMark hm(THREAD);
InstanceKlass* ik = SystemDictionary::RecordComponent_klass();
assert(ik != NULL, "must be loaded");
ik->initialize(CHECK_NULL);
Handle element = ik->allocate_instance_handle(CHECK_NULL);
Handle decl_class(THREAD, holder->java_mirror());
java_lang_reflect_RecordComponent::set_clazz(element(), decl_class());
Symbol* name = holder->constants()->symbol_at(component->name_index()); // name_index is a utf8
oop component_name = StringTable::intern(name, CHECK_NULL);
java_lang_reflect_RecordComponent::set_name(element(), component_name);
Symbol* type = holder->constants()->symbol_at(component->descriptor_index());
Handle component_type_h =
SystemDictionary::find_java_mirror_for_type(type, holder, SignatureStream::NCDFError, CHECK_NULL);
java_lang_reflect_RecordComponent::set_type(element(), component_type_h());
Method* accessor_method = NULL;
{
// Prepend "()" to type to create the full method signature.
ResourceMark rm(THREAD);
int sig_len = type->utf8_length() + 3; // "()" and null char
char* sig = NEW_RESOURCE_ARRAY(char, sig_len);
jio_snprintf(sig, sig_len, "%c%c%s", JVM_SIGNATURE_FUNC, JVM_SIGNATURE_ENDFUNC, type->as_C_string());
TempNewSymbol full_sig = SymbolTable::new_symbol(sig);
accessor_method = holder->find_instance_method(name, full_sig);
}
if (accessor_method != NULL) {
methodHandle method(THREAD, accessor_method);
oop m = Reflection::new_method(method, false, CHECK_NULL);
java_lang_reflect_RecordComponent::set_accessor(element(), m);
} else {
java_lang_reflect_RecordComponent::set_accessor(element(), NULL);
}
int sig_index = component->generic_signature_index();
if (sig_index > 0) {
Symbol* sig = holder->constants()->symbol_at(sig_index); // sig_index is a utf8
oop component_sig = StringTable::intern(sig, CHECK_NULL);
java_lang_reflect_RecordComponent::set_signature(element(), component_sig);
} else {
java_lang_reflect_RecordComponent::set_signature(element(), NULL);
}
typeArrayOop annotation_oop = Annotations::make_java_array(component->annotations(), CHECK_NULL);
java_lang_reflect_RecordComponent::set_annotations(element(), annotation_oop);
typeArrayOop type_annotation_oop = Annotations::make_java_array(component->type_annotations(), CHECK_NULL);
java_lang_reflect_RecordComponent::set_typeAnnotations(element(), type_annotation_oop);
return element();
}
#define CONSTANTPOOL_FIELDS_DO(macro) \
macro(_oop_offset, k, "constantPoolOop", object_signature, false)
@ -4311,6 +4370,13 @@ int java_lang_Short_ShortCache::_static_cache_offset;
int java_lang_Byte_ByteCache::_static_cache_offset;
int java_lang_Boolean::_static_TRUE_offset;
int java_lang_Boolean::_static_FALSE_offset;
int java_lang_reflect_RecordComponent::clazz_offset;
int java_lang_reflect_RecordComponent::name_offset;
int java_lang_reflect_RecordComponent::type_offset;
int java_lang_reflect_RecordComponent::accessor_offset;
int java_lang_reflect_RecordComponent::signature_offset;
int java_lang_reflect_RecordComponent::annotations_offset;
int java_lang_reflect_RecordComponent::typeAnnotations_offset;
@ -4662,6 +4728,55 @@ static int member_offset(int hardcoded_offset) {
return (hardcoded_offset * heapOopSize) + instanceOopDesc::base_offset_in_bytes();
}
#define RECORDCOMPONENT_FIELDS_DO(macro) \
macro(clazz_offset, k, "clazz", class_signature, false); \
macro(name_offset, k, "name", string_signature, false); \
macro(type_offset, k, "type", class_signature, false); \
macro(accessor_offset, k, "accessor", reflect_method_signature, false); \
macro(signature_offset, k, "signature", string_signature, false); \
macro(annotations_offset, k, "annotations", byte_array_signature, false); \
macro(typeAnnotations_offset, k, "typeAnnotations", byte_array_signature, false);
// Support for java_lang_reflect_RecordComponent
void java_lang_reflect_RecordComponent::compute_offsets() {
InstanceKlass* k = SystemDictionary::RecordComponent_klass();
RECORDCOMPONENT_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}
#if INCLUDE_CDS
void java_lang_reflect_RecordComponent::serialize_offsets(SerializeClosure* f) {
RECORDCOMPONENT_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
}
#endif
void java_lang_reflect_RecordComponent::set_clazz(oop element, oop value) {
element->obj_field_put(clazz_offset, value);
}
void java_lang_reflect_RecordComponent::set_name(oop element, oop value) {
element->obj_field_put(name_offset, value);
}
void java_lang_reflect_RecordComponent::set_type(oop element, oop value) {
element->obj_field_put(type_offset, value);
}
void java_lang_reflect_RecordComponent::set_accessor(oop element, oop value) {
element->obj_field_put(accessor_offset, value);
}
void java_lang_reflect_RecordComponent::set_signature(oop element, oop value) {
element->obj_field_put(signature_offset, value);
}
void java_lang_reflect_RecordComponent::set_annotations(oop element, oop value) {
element->obj_field_put(annotations_offset, value);
}
void java_lang_reflect_RecordComponent::set_typeAnnotations(oop element, oop value) {
element->obj_field_put(typeAnnotations_offset, value);
}
// Compute hard-coded offsets
// Invoked before SystemDictionary::initialize, so pre-loaded classes
// are not available to determine the offset_of_static_fields.

View File

@ -30,6 +30,8 @@
#include "oops/oop.hpp"
#include "runtime/os.hpp"
class RecordComponent;
// Interface for manipulating the basic Java classes.
//
// All dependencies on layout of actual Java classes should be kept here.
@ -73,6 +75,7 @@
f(java_lang_reflect_Method) \
f(java_lang_reflect_Constructor) \
f(java_lang_reflect_Field) \
f(java_lang_reflect_RecordComponent) \
f(java_nio_Buffer) \
f(reflect_ConstantPool) \
f(reflect_UnsafeStaticFieldAccessorImpl) \
@ -1483,6 +1486,39 @@ class java_lang_LiveStackFrameInfo: AllStatic {
friend class JavaClasses;
};
// Interface to java.lang.reflect.RecordComponent objects
class java_lang_reflect_RecordComponent: AllStatic {
private:
static int clazz_offset;
static int name_offset;
static int type_offset;
static int accessor_offset;
static int signature_offset;
static int annotations_offset;
static int typeAnnotations_offset;
// Setters
static void set_clazz(oop element, oop value);
static void set_name(oop element, oop value);
static void set_type(oop element, oop value);
static void set_accessor(oop element, oop value);
static void set_signature(oop element, oop value);
static void set_annotations(oop element, oop value);
static void set_typeAnnotations(oop element, oop value);
public:
// Create an instance of RecordComponent
static oop create(InstanceKlass* holder, RecordComponent* component, TRAPS);
static void compute_offsets();
static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN;
// Debugging
friend class JavaClasses;
};
// Interface to java.lang.AssertionStatusDirectives objects
class java_lang_AssertionStatusDirectives: AllStatic {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -88,6 +88,8 @@
"Number of bytes used by the InstanceKlass::inner_classes() array") \
f(nest_members_bytes, IK_nest_members, \
"Number of bytes used by the InstanceKlass::nest_members() array") \
f(record_components_bytes, IK_record_components, \
"Number of bytes used by the InstanceKlass::record_components() array") \
f(signers_bytes, IK_signers, \
"Number of bytes used by the InstanceKlass::singers() array") \
f(class_annotations_bytes, class_annotations, \

View File

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

View File

@ -63,6 +63,7 @@
#include "oops/klass.inline.hpp"
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "oops/recordComponent.hpp"
#include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiRedefineClasses.hpp"
@ -436,6 +437,7 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass
_nest_members(NULL),
_nest_host_index(0),
_nest_host(NULL),
_record_components(NULL),
_static_field_size(parser.static_field_size()),
_nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
_itable_len(parser.itable_size()),
@ -504,6 +506,17 @@ void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data,
}
}
void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data,
Array<RecordComponent*>* record_components) {
if (record_components != NULL && !record_components->is_shared()) {
for (int i = 0; i < record_components->length(); i++) {
RecordComponent* record_component = record_components->at(i);
MetadataFactory::free_metadata(loader_data, record_component);
}
MetadataFactory::free_array<RecordComponent*>(loader_data, record_components);
}
}
// This function deallocates the metadata and C heap pointers that the
// InstanceKlass points to.
void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
@ -532,6 +545,9 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
deallocate_methods(loader_data, methods());
set_methods(NULL);
deallocate_record_components(loader_data, record_components());
set_record_components(NULL);
if (method_ordering() != NULL &&
method_ordering() != Universe::the_empty_int_array() &&
!method_ordering()->is_shared()) {
@ -2339,6 +2355,7 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) {
}
it->push(&_nest_members);
it->push(&_record_components);
}
void InstanceKlass::remove_unshareable_info() {
@ -3270,6 +3287,9 @@ void InstanceKlass::print_on(outputStream* st) const {
}
st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr();
st->print(BULLET"nest members: "); nest_members()->print_value_on(st); st->cr();
if (record_components() != NULL) {
st->print(BULLET"record components: "); record_components()->print_value_on(st); st->cr();
}
if (java_mirror() != NULL) {
st->print(BULLET"java mirror: ");
java_mirror()->print_value_on(st);
@ -3532,6 +3552,7 @@ void InstanceKlass::collect_statistics(KlassSizeStats *sz) const {
n += (sz->_fields_bytes = sz->count_array(fields()));
n += (sz->_inner_classes_bytes = sz->count_array(inner_classes()));
n += (sz->_nest_members_bytes = sz->count_array(nest_members()));
n += (sz->_record_components_bytes = sz->count_array(record_components()));
sz->_ro_bytes += n;
const ConstantPool* cp = constants();
@ -3554,6 +3575,17 @@ void InstanceKlass::collect_statistics(KlassSizeStats *sz) const {
}
}
}
const Array<RecordComponent*>* components = record_components();
if (components != NULL) {
for (int i = 0; i < components->length(); i++) {
RecordComponent* component = components->at(i);
if (component != NULL) {
component->collect_statistics(sz);
}
}
}
}
#endif // INCLUDE_SERVICES

View File

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

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/instanceKlass.hpp"
#include "oops/method.hpp"
#include "oops/recordComponent.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
@ -1693,6 +1694,54 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
}
JVM_END
JVM_ENTRY(jboolean, JVM_IsRecord(JNIEnv *env, jclass cls))
{
JVMWrapper("JVM_IsRecord");
Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls));
if (k != NULL && k->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(k);
return ik->is_record();
} else {
return false;
}
}
JVM_END
JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass))
{
JVMWrapper("JVM_GetRecordComponents");
Klass* c = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(ofClass));
assert(c->is_instance_klass(), "must be");
InstanceKlass* ik = InstanceKlass::cast(c);
if (ik->is_record()) {
Array<RecordComponent*>* components = ik->record_components();
assert(components != NULL, "components should not be NULL");
{
JvmtiVMObjectAllocEventCollector oam;
constantPoolHandle cp(THREAD, ik->constants());
int length = components->length();
assert(length >= 0, "unexpected record_components length");
objArrayOop record_components =
oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), length, CHECK_NULL);
objArrayHandle components_h (THREAD, record_components);
for (int x = 0; x < length; x++) {
RecordComponent* component = components->at(x);
assert(component != NULL, "unexpected NULL record component");
oop component_oop = java_lang_reflect_RecordComponent::create(ik, component, CHECK_NULL);
components_h->obj_at_put(x, component_oop);
}
return (jobjectArray)JNIHandles::make_local(components_h());
}
}
// Return empty array if ofClass is not a record.
objArrayOop result = oopFactory::new_objArray(SystemDictionary::RecordComponent_klass(), 0, CHECK_NULL);
return (jobjectArray)JNIHandles::make_local(env, result);
}
JVM_END
static bool select_method(const methodHandle& method, bool want_constructor) {
if (want_constructor) {
return (method->is_initializer() && !method->is_static());

View File

@ -7633,8 +7633,8 @@ class C2 extends C1 implements I2 {
(unless explicitly prohibited).
The retransformation must not add, remove or rename fields or methods, change the
signatures of methods, change modifiers, or change inheritance.
The retransformation must not change the <code>NestHost</code> or
<code>NestMembers</code> attributes.
The retransformation must not change the <code>NestHost</code>,
<code>NestMembers</code>, or <code>Record</code> attributes.
These restrictions may be lifted in future versions.
See the error return description below for information on error codes
returned if an unsupported retransformation is attempted.
@ -7786,8 +7786,8 @@ class C2 extends C1 implements I2 {
(unless explicitly prohibited).
The redefinition must not add, remove or rename fields or methods, change the
signatures of methods, change modifiers, or change inheritance.
The retransformation must not change the <code>NestHost</code> or
<code>NestMembers</code> attributes.
The redefinition must not change the <code>NestHost</code>,
<code>NestMembers</code>, or <code>Record</code> attributes.
These restrictions may be lifted in future versions.
See the error return description below for information on error codes
returned if an unsupported redefinition is attempted.
@ -14974,6 +14974,11 @@ typedef void (JNICALL *jvmtiEventVMInit)
- The specified thread must be suspended or must be the current thread.
(It was not allowed to be the current thread before.)
</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>
</specification>

View File

@ -27,6 +27,7 @@
#include "interpreter/bytecodeStream.hpp"
#include "memory/universe.hpp"
#include "oops/fieldStreams.inline.hpp"
#include "oops/recordComponent.hpp"
#include "prims/jvmtiClassFileReconstituter.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/signature.hpp"
@ -423,6 +424,57 @@ void JvmtiClassFileReconstituter::write_nest_members_attribute() {
}
}
// Record {
// u2 attribute_name_index;
// u4 attribute_length;
// u2 components_count;
// component_info components[components_count];
// }
// component_info {
// u2 name_index;
// u2 descriptor_index
// u2 attributes_count;
// attribute_info_attributes[attributes_count];
// }
void JvmtiClassFileReconstituter::write_record_attribute() {
Array<RecordComponent*>* components = ik()->record_components();
int number_of_components = components->length();
// Each component has a u2 for name, descr, attribute count
int length = sizeof(u2) + (sizeof(u2) * 3 * number_of_components);
for (int x = 0; x < number_of_components; x++) {
RecordComponent* component = components->at(x);
if (component->generic_signature_index() != 0) {
length += 8; // Signature attribute size
assert(component->attributes_count() > 0, "Bad component attributes count");
}
if (component->annotations() != NULL) {
length += 6 + component->annotations()->length();
}
if (component->type_annotations() != NULL) {
length += 6 + component->type_annotations()->length();
}
}
write_attribute_name_index("Record");
write_u4(length);
write_u2(number_of_components);
for (int i = 0; i < number_of_components; i++) {
RecordComponent* component = components->at(i);
write_u2(component->name_index());
write_u2(component->descriptor_index());
write_u2(component->attributes_count());
if (component->generic_signature_index() != 0) {
write_signature_attribute(component->generic_signature_index());
}
if (component->annotations() != NULL) {
write_annotations_attribute("RuntimeVisibleAnnotations", component->annotations());
}
if (component->type_annotations() != NULL) {
write_annotations_attribute("RuntimeVisibleTypeAnnotations", component->type_annotations());
}
}
}
// Write InnerClasses attribute
// JVMSpec| InnerClasses_attribute {
@ -699,6 +751,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if (ik()->nest_members() != Universe::the_empty_short_array()) {
++attr_count;
}
if (ik()->record_components() != NULL) {
++attr_count;
}
write_u2(attr_count);
@ -729,6 +784,9 @@ void JvmtiClassFileReconstituter::write_class_attributes() {
if (ik()->nest_members() != Universe::the_empty_short_array()) {
write_nest_members_attribute();
}
if (ik()->record_components() != NULL) {
write_record_attribute();
}
}
// Write the method information portion of ClassFile structure

View File

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

View File

@ -40,10 +40,12 @@
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/annotations.hpp"
#include "oops/constantPool.hpp"
#include "oops/fieldStreams.inline.hpp"
#include "oops/klassVtable.hpp"
#include "oops/oop.inline.hpp"
#include "oops/recordComponent.hpp"
#include "prims/jvmtiImpl.hpp"
#include "prims/jvmtiRedefineClasses.hpp"
#include "prims/jvmtiThreadState.inline.hpp"
@ -785,6 +787,69 @@ static jvmtiError check_nest_attributes(InstanceKlass* the_class,
return JVMTI_ERROR_NONE;
}
// Return an error status if the class Record attribute was changed.
static jvmtiError check_record_attribute(InstanceKlass* the_class, InstanceKlass* scratch_class) {
// Get lists of record components.
Array<RecordComponent*>* the_record = the_class->record_components();
Array<RecordComponent*>* scr_record = scratch_class->record_components();
bool the_record_exists = the_record != NULL;
bool scr_record_exists = scr_record != NULL;
if (the_record_exists && scr_record_exists) {
int the_num_components = the_record->length();
int scr_num_components = scr_record->length();
if (the_num_components != scr_num_components) {
log_trace(redefine, class, record)
("redefined class %s attribute change error: Record num_components=%d changed to num_components=%d",
the_class->external_name(), the_num_components, scr_num_components);
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
}
// Compare each field in each record component.
ConstantPool* the_cp = the_class->constants();
ConstantPool* scr_cp = scratch_class->constants();
for (int x = 0; x < the_num_components; x++) {
RecordComponent* the_component = the_record->at(x);
RecordComponent* scr_component = scr_record->at(x);
const Symbol* const the_name = the_cp->symbol_at(the_component->name_index());
const Symbol* const scr_name = scr_cp->symbol_at(scr_component->name_index());
const Symbol* const the_descr = the_cp->symbol_at(the_component->descriptor_index());
const Symbol* const scr_descr = scr_cp->symbol_at(scr_component->descriptor_index());
if (the_name != scr_name || the_descr != scr_descr) {
log_trace(redefine, class, record)
("redefined class %s attribute change error: Record name_index, descriptor_index, and/or attributes_count changed",
the_class->external_name());
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
}
int the_gen_sig = the_component->generic_signature_index();
int scr_gen_sig = scr_component->generic_signature_index();
const Symbol* const the_gen_sig_sym = (the_gen_sig == 0 ? NULL :
the_cp->symbol_at(the_component->generic_signature_index()));
const Symbol* const scr_gen_sig_sym = (scr_gen_sig == 0 ? NULL :
scr_cp->symbol_at(scr_component->generic_signature_index()));
if (the_gen_sig_sym != scr_gen_sig_sym) {
log_trace(redefine, class, record)
("redefined class %s attribute change error: Record generic_signature attribute changed",
the_class->external_name());
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
}
// It's okay if a record component's annotations were changed.
}
} else if (the_record_exists ^ scr_record_exists) {
const char* action_str = (the_record_exists) ? "removed" : "added";
log_trace(redefine, class, record)
("redefined class %s attribute change error: Record attribute %s",
the_class->external_name(), action_str);
return JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED;
}
return JVMTI_ERROR_NONE;
}
static bool can_add_or_delete(Method* m) {
// Compatibility mode
return (AllowRedefinitionToAddDeleteMethods &&
@ -838,6 +903,12 @@ jvmtiError VM_RedefineClasses::compare_and_normalize_class_versions(
return err;
}
// Check whether the Record attribute has been changed.
err = check_record_attribute(the_class, scratch_class);
if (err != JVMTI_ERROR_NONE) {
return err;
}
// Check whether class modifiers are the same.
jushort old_flags = (jushort) the_class->access_flags().get_flags();
jushort new_flags = (jushort) scratch_class->access_flags().get_flags();
@ -1711,6 +1782,12 @@ bool VM_RedefineClasses::rewrite_cp_refs(InstanceKlass* scratch_class,
return false;
}
// rewrite constant pool references in the Record attribute:
if (!rewrite_cp_refs_in_record_attribute(scratch_class, THREAD)) {
// propagate failure back to caller
return false;
}
// rewrite constant pool references in the methods:
if (!rewrite_cp_refs_in_methods(scratch_class, THREAD)) {
// propagate failure back to caller
@ -1809,6 +1886,46 @@ bool VM_RedefineClasses::rewrite_cp_refs_in_nest_attributes(
return true;
}
// Rewrite constant pool references in the Record attribute.
bool VM_RedefineClasses::rewrite_cp_refs_in_record_attribute(
InstanceKlass* scratch_class, TRAPS) {
Array<RecordComponent*>* components = scratch_class->record_components();
if (components != NULL) {
for (int i = 0; i < components->length(); i++) {
RecordComponent* component = components->at(i);
u2 cp_index = component->name_index();
component->set_name_index(find_new_index(cp_index));
cp_index = component->descriptor_index();
component->set_descriptor_index(find_new_index(cp_index));
cp_index = component->generic_signature_index();
if (cp_index != 0) {
component->set_generic_signature_index(find_new_index(cp_index));
}
AnnotationArray* annotations = component->annotations();
if (annotations != NULL && annotations->length() != 0) {
int byte_i = 0; // byte index into annotations
if (!rewrite_cp_refs_in_annotations_typeArray(annotations, byte_i, THREAD)) {
log_debug(redefine, class, annotation)("bad record_component_annotations at %d", i);
// propagate failure back to caller
return false;
}
}
AnnotationArray* type_annotations = component->type_annotations();
if (type_annotations != NULL && type_annotations->length() != 0) {
int byte_i = 0; // byte index into annotations
if (!rewrite_cp_refs_in_annotations_typeArray(type_annotations, byte_i, THREAD)) {
log_debug(redefine, class, annotation)("bad record_component_type_annotations at %d", i);
// propagate failure back to caller
return false;
}
}
}
}
return true;
}
// Rewrite constant pool references in the methods.
bool VM_RedefineClasses::rewrite_cp_refs_in_methods(
InstanceKlass* scratch_class, TRAPS) {

View File

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

View File

@ -26,7 +26,9 @@
package java.io;
import java.io.ObjectStreamClass.WeakClassKey;
import java.io.ObjectStreamClass.RecordSupport;
import java.lang.System.Logger;
import java.lang.invoke.MethodHandle;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Array;
import java.lang.reflect.Modifier;
@ -218,6 +220,39 @@ import sun.reflect.misc.ReflectUtil;
* Similarly, any serialPersistentFields or serialVersionUID field declarations
* are also ignored--all enum types have a fixed serialVersionUID of 0L.
*
* @implSpec
* <a id="record-serialization"></a>
* Records are serialized differently than ordinary serializable or externalizable
* objects. The serialized form of a record object is a sequence of values derived
* from the record components. The stream format of a record object is the same as
* that of an ordinary object in the stream. During deserialization, if the local
* class equivalent of the specified stream class descriptor is a record class,
* then first the stream fields are read and reconstructed to serve as the record's
* component values; and second, a record object is created by invoking the
* record's <i>canonical</i> constructor with the component values as arguments (or the
* default value for component's type if a component value is absent from the
* stream).
* Like other serializable or externalizable objects, record objects can function
* as the target of back references appearing subsequently in the serialization
* stream. However, a cycle in the graph where the record object is referred to,
* either directly or transitively, by one of its components, is not preserved.
* The record components are deserialized prior to the invocation of the record
* constructor, hence this limitation (see
* <a href="{@docRoot}/../specs/serialization/serial-arch.html#cyclic-references">
* [Section 1.14, "Circular References"</a> for additional information).
* The process by which record objects are serialized or externalized cannot be
* customized; any class-specific writeObject, readObject, readObjectNoData,
* writeExternal, and readExternal methods defined by record classes are
* ignored during serialization and deserialization. However, a substitute object
* to be serialized or a designate replacement may be specified, by the
* writeReplace and readResolve methods, respectively. Any
* serialPersistentFields field declaration is ignored. Documenting serializable
* fields and data for record classes is unnecessary, since there is no variation
* in the serial form, other than whether a substitute or replacement object is
* used. The serialVersionUID of a record class is 0L unless explicitly
* declared. The requirement for matching serialVersionUID values is waived for
* record classes.
*
* @author Mike Warres
* @author Roger Riggs
* @see java.io.DataInput
@ -2047,6 +2082,11 @@ public class ObjectInputStream
return result;
}
@SuppressWarnings("preview")
private static boolean isRecord(Class<?> cls) {
return cls.isRecord();
}
/**
* Reads and returns "ordinary" (i.e., not a String, Class,
* ObjectStreamClass, array, or enum constant) object, or null if object's
@ -2085,7 +2125,12 @@ public class ObjectInputStream
handles.markException(passHandle, resolveEx);
}
if (desc.isExternalizable()) {
final boolean isRecord = cl != null && isRecord(cl) ? true : false;
if (isRecord) {
assert obj == null;
obj = readRecord(desc);
handles.setObject(passHandle, obj);
} else if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
@ -2171,6 +2216,43 @@ public class ObjectInputStream
*/
}
/** Reads a record. */
private Object readRecord(ObjectStreamClass desc) throws IOException {
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
if (slots.length != 1) {
// skip any superclass stream field values
for (int i = 0; i < slots.length-1; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slots[i].hasData) {
defaultReadFields(null, slotDesc);
}
}
}
FieldValues fieldValues = defaultReadFields(null, desc);
// retrieve the canonical constructor
MethodHandle ctrMH = desc.getRecordConstructor();
// bind the stream field values
ctrMH = RecordSupport.bindCtrValues(ctrMH, desc, fieldValues);
try {
return ctrMH.invoke();
} catch (Exception e) {
InvalidObjectException ioe = new InvalidObjectException(e.getMessage());
ioe.initCause(e);
throw ioe;
} catch (Error e) {
throw e;
} catch (Throwable t) {
ObjectStreamException ose = new InvalidObjectException(
"ReflectiveOperationException during deserialization");
ose.initCause(t);
throw ose;
}
}
/**
* Reads (or attempts to skip, if obj is null or is tagged with a
* ClassNotFoundException) instance data for each serializable class of
@ -2317,7 +2399,7 @@ public class ObjectInputStream
}
}
private class FieldValues {
/*package-private*/ class FieldValues {
final byte[] primValues;
final Object[] objValues;

View File

@ -150,6 +150,10 @@ import sun.reflect.misc.ReflectUtil;
* defaultWriteObject and writeFields initially terminate any existing
* block-data record.
*
* @implSpec
* Records are serialized differently than ordinary serializable or externalizable
* objects, see <a href="ObjectInputStream.html#record-serialization">record serialization</a>.
*
* @author Mike Warres
* @author Roger Riggs
* @see java.io.DataOutput
@ -1431,7 +1435,10 @@ public class ObjectOutputStream
bout.writeByte(TC_OBJECT);
writeClassDesc(desc, false);
handles.assign(unshared ? null : obj);
if (desc.isExternalizable() && !desc.isProxy()) {
if (desc.isRecord()) {
writeRecordData(obj, desc);
} else if (desc.isExternalizable() && !desc.isProxy()) {
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc);
@ -1475,6 +1482,21 @@ public class ObjectOutputStream
curPut = oldPut;
}
/** Writes the record component values for the given record object. */
@SuppressWarnings("preview")
private void writeRecordData(Object obj, ObjectStreamClass desc)
throws IOException
{
assert obj.getClass().isRecord();
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
if (slots.length != 1) {
throw new InvalidClassException(
"expected a single record slot length, but found: " + slots.length);
}
defaultWriteFields(obj, desc); // #### seems unnecessary to use the accessors
}
/**
* Writes instance data for each serializable class of given object, from
* superclass to subclass.

View File

@ -25,6 +25,8 @@
package java.io;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
@ -32,6 +34,7 @@ import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.RecordComponent;
import java.lang.reflect.UndeclaredThrowableException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
@ -44,6 +47,8 @@ import java.security.NoSuchAlgorithmException;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
@ -123,6 +128,8 @@ public class ObjectStreamClass implements Serializable {
private boolean isProxy;
/** true if represents enum type */
private boolean isEnum;
/** true if represents record type */
private boolean isRecord;
/** true if represented class implements Serializable */
private boolean serializable;
/** true if represented class implements Externalizable */
@ -184,6 +191,8 @@ public class ObjectStreamClass implements Serializable {
/** serialization-appropriate constructor, or null if none */
private Constructor<?> cons;
/** record canonical constructor, or null */
private MethodHandle canonicalCtr;
/** protection domains that need to be checked when calling the constructor */
private ProtectionDomain[] domains;
@ -261,6 +270,9 @@ public class ObjectStreamClass implements Serializable {
public long getSerialVersionUID() {
// REMIND: synchronize instead of relying on volatile?
if (suid == null) {
if (isRecord)
return 0L;
suid = AccessController.doPrivileged(
new PrivilegedAction<Long>() {
public Long run() {
@ -467,6 +479,11 @@ public class ObjectStreamClass implements Serializable {
}
}
@SuppressWarnings("preview")
private static boolean isRecord(Class<?> cls) {
return cls.isRecord();
}
/**
* Creates local class descriptor representing given class.
*/
@ -475,6 +492,7 @@ public class ObjectStreamClass implements Serializable {
name = cl.getName();
isProxy = Proxy.isProxyClass(cl);
isEnum = Enum.class.isAssignableFrom(cl);
isRecord = isRecord(cl);
serializable = Serializable.class.isAssignableFrom(cl);
externalizable = Externalizable.class.isAssignableFrom(cl);
@ -505,7 +523,9 @@ public class ObjectStreamClass implements Serializable {
fields = NO_FIELDS;
}
if (externalizable) {
if (isRecord) {
canonicalCtr = canonicalRecordCtr(cl);
} else if (externalizable) {
cons = getExternalizableConstructor(cl);
} else {
cons = getSerializableConstructor(cl);
@ -542,16 +562,20 @@ public class ObjectStreamClass implements Serializable {
if (deserializeEx == null) {
if (isEnum) {
deserializeEx = new ExceptionInfo(name, "enum type");
} else if (cons == null) {
} else if (cons == null && !isRecord) {
deserializeEx = new ExceptionInfo(name, "no valid constructor");
}
}
if (isRecord && canonicalCtr == null) {
deserializeEx = new ExceptionInfo(name, "record canonical constructor not found");
} else {
for (int i = 0; i < fields.length; i++) {
if (fields[i].getField() == null) {
defaultSerializeEx = new ExceptionInfo(
name, "unmatched serializable field(s) declared");
}
}
}
initialized = true;
}
@ -682,7 +706,7 @@ public class ObjectStreamClass implements Serializable {
}
if (model.serializable == osc.serializable &&
!cl.isArray() &&
!cl.isArray() && !isRecord(cl) &&
suid != osc.getSerialVersionUID()) {
throw new InvalidClassException(osc.name,
"local class incompatible: " +
@ -714,6 +738,10 @@ public class ObjectStreamClass implements Serializable {
}
this.cl = cl;
if (cl != null) {
this.isRecord = isRecord(cl);
this.canonicalCtr = osc.canonicalCtr;
}
this.resolveEx = resolveEx;
this.superDesc = superDesc;
name = model.name;
@ -739,12 +767,14 @@ public class ObjectStreamClass implements Serializable {
deserializeEx = localDesc.deserializeEx;
}
domains = localDesc.domains;
assert isRecord(cl) ? localDesc.cons == null : true;
cons = localDesc.cons;
}
fieldRefl = getReflector(fields, localDesc);
// reassign to matched fields so as to reflect local unshared settings
fields = fieldRefl.getFields();
initialized = true;
}
@ -966,6 +996,15 @@ public class ObjectStreamClass implements Serializable {
return isEnum;
}
/**
* Returns true if class descriptor represents a record type, false
* otherwise.
*/
boolean isRecord() {
requireInitialized();
return isRecord;
}
/**
* Returns true if represented class implements Externalizable, false
* otherwise.
@ -1518,6 +1557,37 @@ public class ObjectStreamClass implements Serializable {
return reflFactory.newConstructorForSerialization(cl);
}
/**
* Returns the canonical constructor for the given record class, or null if
* the not found ( which should never happen for correctly generated record
* classes ).
*/
@SuppressWarnings("preview")
private static MethodHandle canonicalRecordCtr(Class<?> cls) {
assert isRecord(cls) : "Expected record, got: " + cls;
PrivilegedAction<MethodHandle> pa = () -> {
Class<?>[] paramTypes = Arrays.stream(cls.getRecordComponents())
.map(RecordComponent::getType)
.toArray(Class<?>[]::new);
try {
Constructor<?> ctr = cls.getConstructor(paramTypes);
ctr.setAccessible(true);
return MethodHandles.lookup().unreflectConstructor(ctr);
} catch (IllegalAccessException | NoSuchMethodException e) {
return null;
}
};
return AccessController.doPrivileged(pa);
}
/**
* Returns the canonical constructor, if the local class equivalent of this
* stream class descriptor is a record class, otherwise null.
*/
MethodHandle getRecordConstructor() {
return canonicalCtr;
}
/**
* Returns non-static, non-abstract method with given signature provided it
* is defined by or accessible (via inheritance) by the given class, or
@ -1641,12 +1711,16 @@ public class ObjectStreamClass implements Serializable {
private static ObjectStreamField[] getSerialFields(Class<?> cl)
throws InvalidClassException
{
if (!Serializable.class.isAssignableFrom(cl))
return NO_FIELDS;
ObjectStreamField[] fields;
if (Serializable.class.isAssignableFrom(cl) &&
!Externalizable.class.isAssignableFrom(cl) &&
if (isRecord(cl)) {
fields = getDefaultSerialFields(cl);
Arrays.sort(fields);
} else if (!Externalizable.class.isAssignableFrom(cl) &&
!Proxy.isProxyClass(cl) &&
!cl.isInterface())
{
!cl.isInterface()) {
if ((fields = getDeclaredSerialFields(cl)) == null) {
fields = getDefaultSerialFields(cl);
}
@ -2438,4 +2512,115 @@ public class ObjectStreamClass implements Serializable {
}
}
}
/** Record specific support for retrieving and binding stream field values. */
static final class RecordSupport {
/** Binds the given stream field values to the given method handle. */
@SuppressWarnings("preview")
static MethodHandle bindCtrValues(MethodHandle ctrMH,
ObjectStreamClass desc,
ObjectInputStream.FieldValues fieldValues) {
RecordComponent[] recordComponents;
try {
Class<?> cls = desc.forClass();
PrivilegedExceptionAction<RecordComponent[]> pa = cls::getRecordComponents;
recordComponents = AccessController.doPrivileged(pa);
} catch (PrivilegedActionException e) {
throw new InternalError(e.getCause());
}
Object[] args = new Object[recordComponents.length];
for (int i = 0; i < recordComponents.length; i++) {
String name = recordComponents[i].getName();
Class<?> type= recordComponents[i].getType();
Object o = streamFieldValue(name, type, desc, fieldValues);
args[i] = o;
}
return MethodHandles.insertArguments(ctrMH, 0, args);
}
/** Returns the number of primitive fields for the given descriptor. */
private static int numberPrimValues(ObjectStreamClass desc) {
ObjectStreamField[] fields = desc.getFields();
int primValueCount = 0;
for (int i = 0; i < fields.length; i++) {
if (fields[i].isPrimitive())
primValueCount++;
else
break; // can be no more
}
return primValueCount;
}
/** Returns the default value for the given type. */
private static Object defaultValueFor(Class<?> pType) {
if (pType == Integer.TYPE)
return 0;
else if (pType == Byte.TYPE)
return (byte)0;
else if (pType == Long.TYPE)
return 0L;
else if (pType == Float.TYPE)
return 0.0f;
else if (pType == Double.TYPE)
return 0.0d;
else if (pType == Short.TYPE)
return (short)0;
else if (pType == Character.TYPE)
return '\u0000';
else if (pType == Boolean.TYPE)
return false;
else
return null;
}
/**
* Returns the stream field value for the given name. The default value
* for the given type is returned if the field value is absent.
*/
private static Object streamFieldValue(String pName,
Class<?> pType,
ObjectStreamClass desc,
ObjectInputStream.FieldValues fieldValues) {
ObjectStreamField[] fields = desc.getFields();
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i];
String fName = f.getName();
if (!fName.equals(pName))
continue;
Class<?> fType = f.getField().getType();
if (!pType.isAssignableFrom(fType))
throw new InternalError(fName + " unassignable, pType:" + pType + ", fType:" + fType);
if (f.isPrimitive()) {
if (pType == Integer.TYPE)
return Bits.getInt(fieldValues.primValues, f.getOffset());
else if (fType == Byte.TYPE)
return fieldValues.primValues[f.getOffset()];
else if (fType == Long.TYPE)
return Bits.getLong(fieldValues.primValues, f.getOffset());
else if (fType == Float.TYPE)
return Bits.getFloat(fieldValues.primValues, f.getOffset());
else if (fType == Double.TYPE)
return Bits.getDouble(fieldValues.primValues, f.getOffset());
else if (fType == Short.TYPE)
return Bits.getShort(fieldValues.primValues, f.getOffset());
else if (fType == Character.TYPE)
return Bits.getChar(fieldValues.primValues, f.getOffset());
else if (fType == Boolean.TYPE)
return Bits.getBoolean(fieldValues.primValues, f.getOffset());
else
throw new InternalError("Unexpected type: " + fType);
} else { // reference
return fieldValues.objValues[i - numberPrimValues(desc)];
}
}
return defaultValueFor(pType);
}
}
}

View File

@ -46,6 +46,7 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.RecordComponent;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.constant.Constable;
@ -2259,6 +2260,68 @@ public final class Class<T> implements java.io.Serializable,
return copyFields(privateGetDeclaredFields(false));
}
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns an array containing {@code RecordComponent} objects reflecting all the
* declared record components of the record represented by this {@code Class} object.
* The components are returned in the same order that they are declared in the
* record header.
*
* @return The array of {@code RecordComponent} objects representing all the
* record components of this record. The array is empty if this class
* is not a record, or if this class is a record with no components.
* @throws SecurityException
* If a security manager, <i>s</i>, is present and any of the
* following conditions is met:
*
* <ul>
*
* <li> the caller's class loader is not the same as the
* class loader of this class and invocation of
* {@link SecurityManager#checkPermission
* s.checkPermission} method with
* {@code RuntimePermission("accessDeclaredMembers")}
* denies access to the declared methods within this class
*
* <li> the caller's class loader is not the same as or an
* ancestor of the class loader for the current class and
* invocation of {@link SecurityManager#checkPackageAccess
* s.checkPackageAccess()} denies access to the package
* of this class
*
* </ul>
*
* @jls 8.10 Record Types
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
@SuppressWarnings("preview")
@CallerSensitive
public RecordComponent[] getRecordComponents() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
}
if (isPrimitive() || isArray()) {
return new RecordComponent[0];
}
Object[] recordComponents = getRecordComponents0();
if (recordComponents == null || recordComponents.length == 0) {
return new RecordComponent[0];
}
RecordComponent[] result = new RecordComponent[recordComponents.length];
for (int i = 0; i < recordComponents.length; i++) {
result[i] = (RecordComponent)recordComponents[i];
}
return result;
}
/**
* Returns an array containing {@code Method} objects reflecting all the
@ -3417,6 +3480,8 @@ public final class Class<T> implements java.io.Serializable,
private native Method[] getDeclaredMethods0(boolean publicOnly);
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
private native Class<?>[] getDeclaredClasses0();
private native Object[] getRecordComponents0();
private native boolean isRecord0();
/**
* Helper method to get the method name from arguments.
@ -3525,6 +3590,29 @@ public final class Class<T> implements java.io.Serializable,
this.getSuperclass() == java.lang.Enum.class;
}
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns {@code true} if and only if this class is a record class.
* It returns {@code false} otherwise. Note that class {@link Record} is not a
* record type and thus invoking this method on class {@link java.lang.Record}
* returns {@code false}.
*
* @return true if and only if this class is a record class
* @jls 8.10 Record Types
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
public boolean isRecord() {
return isRecord0();
}
// Fetches the factory for reflective objects
private static ReflectionFactory getReflectionFactory() {
if (reflectionFactory == null) {

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -114,5 +114,25 @@ public enum ElementType {
*
* @since 9
*/
MODULE
MODULE,
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This constant is associated with <i>records</i>, a preview
* feature of the Java language. Programs can only use this
* constant when preview features are enabled. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Record component
*
* @jls 8.10.3 Record Members
* @jls 9.7.4 Where Annotations May Appear
*
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=true)
RECORD_COMPONENT;
}

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 {
PATTERN_MATCHING_IN_INSTANCEOF,
TEXT_BLOCKS,
RECORDS,
;
}
}

View File

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

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -90,7 +90,19 @@ public final class TypeAnnotation {
METHOD_RETURN,
METHOD_RECEIVER,
METHOD_FORMAL_PARAMETER,
THROWS;
THROWS,
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This enum constant is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
RECORD_COMPONENT;
}
public static final class TypeAnnotationTargetInfo {

View File

@ -38,6 +38,10 @@
#include "check_classname.h"
#include "java_lang_Class.h"
/* defined in libverify.so/verify.dll (src file common/check_format.c) */
extern jboolean VerifyClassname(char *utf_name, jboolean arrayAllowed);
extern jboolean VerifyFixClassname(char *utf_name);
#define OBJ "Ljava/lang/Object;"
#define CLS "Ljava/lang/Class;"
#define CPL "Ljdk/internal/reflect/ConstantPool;"
@ -73,6 +77,8 @@ static JNINativeMethod methods[] = {
{"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations},
{"getNestHost0", "()" CLS, (void *)&JVM_GetNestHost},
{"getNestMembers0", "()[" CLS, (void *)&JVM_GetNestMembers},
{"getRecordComponents0", "()[" OBJ, (void *)&JVM_GetRecordComponents},
{"isRecord0", "()Z", (void *)&JVM_IsRecord},
};
#undef OBJ

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

View File

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

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -46,8 +46,12 @@ public enum ElementKind {
// Declared types
/** An enum type. */
ENUM,
/** A class not described by a more specific kind (like {@code ENUM}). */
/**
* A class not described by a more specific kind (like {@code
* ENUM} or {@code RECORD}).
*/
CLASS,
/** An annotation type. */
ANNOTATION_TYPE,
/**
@ -90,6 +94,8 @@ public enum ElementKind {
*/
OTHER,
// Constants added since initial release
/**
* A resource variable.
* @since 1.7
@ -101,17 +107,47 @@ public enum ElementKind {
* @since 9
* @spec JPMS
*/
MODULE;
MODULE,
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This enum constant is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* A record type.
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
RECORD,
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This enum constant is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* A record component of a {@code record}.
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
RECORD_COMPONENT;
/**
* Returns {@code true} if this is a kind of class:
* either {@code CLASS} or {@code ENUM}.
* either {@code CLASS} or {@code ENUM} or {@code RECORD}.
*
* @return {@code true} if this is a kind of class
*/
@SuppressWarnings("preview")
public boolean isClass() {
return this == CLASS || this == ENUM;
return this == CLASS || this == ENUM || this == RECORD;
}
/**

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -164,4 +164,29 @@ public interface ElementVisitor<R, P> {
default R visitModule(ModuleElement e, P p) {
return visitUnknown(e, p);
}
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Visits a record component element.
*
* @implSpec The default implementation visits a {@code
* RecordComponentElement} by calling {@code visitUnknown(e, p)}.
*
* @param e the element to visit
* @param p a visitor-specified parameter
* @return a visitor-specified result
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
@SuppressWarnings("preview")
default R visitRecordComponent(RecordComponentElement e, P p) {
return visitUnknown(e, p);
}
}

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
* to information about the type and its members. Note that an enum
* type is a kind of class and an annotation type is a kind of
* type and a record type are kinds of classes and an annotation type is a kind of
* interface.
*
* <p> While a {@code TypeElement} represents a class or interface
@ -82,8 +82,9 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
TypeMirror asType();
/**
* Returns the fields, methods, constructors, and member types
* that are directly declared in this class or interface.
* Returns the fields, methods, constructors, record components,
* and member types that are directly declared in this class or
* interface.
*
* This includes any {@linkplain Elements.Origin#MANDATED
* mandated} elements such as the (implicit) default constructor
@ -177,6 +178,32 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable
*/
List<? extends TypeParameterElement> getTypeParameters();
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns the record components of this type element in
* declaration order.
*
* @implSpec The default implementations of this method returns an
* empty and unmodifiable list.
*
* @return the record components, or an empty list if there are
* none
*
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
@SuppressWarnings("preview")
default List<? extends RecordComponentElement> getRecordComponents() {
return List.of();
}
/**
* Returns the package of a top-level type and returns the
* immediately lexically enclosing element for a {@linkplain

View File

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

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -64,6 +64,7 @@ import javax.annotation.processing.SupportedSourceVersion;
* @see AbstractAnnotationValueVisitor7
* @see AbstractAnnotationValueVisitor8
* @see AbstractAnnotationValueVisitor9
* @see AbstractAnnotationValueVisitor14
* @since 1.6
*/
@SupportedSourceVersion(RELEASE_6)

View File

@ -57,6 +57,7 @@ import javax.annotation.processing.SupportedSourceVersion;
* @see AbstractAnnotationValueVisitor6
* @see AbstractAnnotationValueVisitor8
* @see AbstractAnnotationValueVisitor9
* @see AbstractAnnotationValueVisitor14
* @since 1.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.
*
* This code is free software; you can redistribute it and/or modify it
@ -57,6 +57,7 @@ import javax.annotation.processing.SupportedSourceVersion;
* @see AbstractAnnotationValueVisitor6
* @see AbstractAnnotationValueVisitor7
* @see AbstractAnnotationValueVisitor9
* @see AbstractAnnotationValueVisitor14
* @since 1.8
*/
@SupportedSourceVersion(RELEASE_8)

View File

@ -57,6 +57,7 @@ import javax.annotation.processing.SupportedSourceVersion;
* @see AbstractAnnotationValueVisitor6
* @see AbstractAnnotationValueVisitor7
* @see AbstractAnnotationValueVisitor8
* @see AbstractAnnotationValueVisitor14
* @since 9
*/
@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.
*
* This code is free software; you can redistribute it and/or modify it
@ -66,6 +66,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractElementVisitor7
* @see AbstractElementVisitor8
* @see AbstractElementVisitor9
* @see AbstractElementVisitor14
* @since 1.6
*/
@SupportedSourceVersion(RELEASE_6)
@ -143,4 +144,23 @@ public abstract class AbstractElementVisitor6<R, P> implements ElementVisitor<R,
// Use implementation from interface default method
return ElementVisitor.super.visitModule(e, p);
}
/**
* {@inheritDoc}
*
* @implSpec Visits a {@code RecordComponentElement} by calling {@code
* visitUnknown}.
*
* @param e {@inheritDoc}
* @param p {@inheritDoc}
* @return {@inheritDoc}
*
* @since 14
*/
@SuppressWarnings("preview")
@Override
public R visitRecordComponent(RecordComponentElement e, P p) {
// Use implementation from interface default method
return ElementVisitor.super.visitRecordComponent(e, p);
}
}

View File

@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractElementVisitor6
* @see AbstractElementVisitor8
* @see AbstractElementVisitor9
* @see AbstractElementVisitor14
* @since 1.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.
*
* This code is free software; you can redistribute it and/or modify it
@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractElementVisitor6
* @see AbstractElementVisitor7
* @see AbstractElementVisitor9
* @see AbstractElementVisitor14
* @since 1.8
*/
@SupportedSourceVersion(RELEASE_8)

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -65,6 +65,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractTypeVisitor7
* @see AbstractTypeVisitor8
* @see AbstractTypeVisitor9
* @see AbstractTypeVisitor14
* @since 1.6
*/
@SupportedSourceVersion(RELEASE_6)

View File

@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractTypeVisitor6
* @see AbstractTypeVisitor8
* @see AbstractTypeVisitor9
* @see AbstractTypeVisitor14
* @since 1.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.
*
* This code is free software; you can redistribute it and/or modify it
@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractTypeVisitor6
* @see AbstractTypeVisitor7
* @see AbstractTypeVisitor9
* @see AbstractTypeVisitor14
* @since 1.8
*/
@SupportedSourceVersion(RELEASE_8)

View File

@ -61,6 +61,7 @@ import static javax.lang.model.SourceVersion.*;
* @see AbstractTypeVisitor6
* @see AbstractTypeVisitor7
* @see AbstractTypeVisitor8
* @see AbstractTypeVisitor14
* @since 9
*/
@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.
*
* This code is free software; you can redistribute it and/or modify it
@ -79,11 +79,18 @@ public class ElementFilter {
private static final Set<ElementKind> MODULE_KIND =
Collections.unmodifiableSet(EnumSet.of(ElementKind.MODULE));
@SuppressWarnings("preview")
private static final Set<ElementKind> TYPE_KINDS =
Collections.unmodifiableSet(EnumSet.of(ElementKind.CLASS,
ElementKind.ENUM,
ElementKind.INTERFACE,
ElementKind.RECORD,
ElementKind.ANNOTATION_TYPE));
@SuppressWarnings("preview")
private static final Set<ElementKind> RECORD_COMPONENT_KIND =
Set.of(ElementKind.RECORD_COMPONENT);
/**
* Returns a list of fields in {@code elements}.
* @return a list of fields in {@code elements}
@ -104,6 +111,48 @@ public class ElementFilter {
return setFilter(elements, FIELD_KINDS, VariableElement.class);
}
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns a list of record components in {@code elements}.
* @return a list of record components in {@code elements}
* @param elements the elements to filter
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
@SuppressWarnings("preview")
public static List<RecordComponentElement>
recordComponentsIn(Iterable<? extends Element> elements) {
return listFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class);
}
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns a set of record components in {@code elements}.
* @return a set of record components in {@code elements}
* @param elements the elements to filter
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
@SuppressWarnings("preview")
public static Set<RecordComponentElement>
recordComponentsIn(Set<? extends Element> elements) {
return setFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class);
}
/**
* Returns a list of constructors in {@code elements}.
* @return a list of constructors in {@code elements}

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -80,6 +80,7 @@ import javax.lang.model.SourceVersion;
* @see ElementKindVisitor7
* @see ElementKindVisitor8
* @see ElementKindVisitor9
* @see ElementKindVisitor14
* @since 1.6
*/
@SupportedSourceVersion(RELEASE_6)
@ -138,6 +139,7 @@ public class ElementKindVisitor6<R, P>
* @param p {@inheritDoc}
* @return the result of the kind-specific visit method
*/
@SuppressWarnings("preview")
@Override
public R visitType(TypeElement e, P p) {
ElementKind k = e.getKind();
@ -154,6 +156,9 @@ public class ElementKindVisitor6<R, P>
case INTERFACE:
return visitTypeAsInterface(e, p);
case RECORD:
return visitTypeAsRecord(e, p);
default:
throw new AssertionError("Bad kind " + k + " for TypeElement" + e);
}
@ -211,6 +216,30 @@ public class ElementKindVisitor6<R, P>
return defaultAction(e, p);
}
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Visits a {@code RECORD} type element.
*
* @implSpec This implementation calls {@code visitUnknown}.
*.
* @param e the element to visit
* @param p a visitor-specified parameter
* @return the result of {@code visitUnknown}
*
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
public R visitTypeAsRecord(TypeElement e, P p) {
return visitUnknown(e, p);
}
/**
* Visits a variable element
*

View File

@ -74,6 +74,7 @@ import static javax.lang.model.SourceVersion.*;
* @see ElementKindVisitor6
* @see ElementKindVisitor8
* @see ElementKindVisitor9
* @see ElementKindVisitor14
* @since 1.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.
*
* This code is free software; you can redistribute it and/or modify it
@ -74,6 +74,7 @@ import javax.lang.model.SourceVersion;
* @see ElementKindVisitor6
* @see ElementKindVisitor7
* @see ElementKindVisitor9
* @see ElementKindVisitor14
* @since 1.8
*/
@SupportedSourceVersion(RELEASE_8)

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 ElementScanner8
* @see ElementScanner9
* @see ElementScanner14
* @since 1.6
*/
@SupportedSourceVersion(RELEASE_6)

View File

@ -87,6 +87,7 @@ import static javax.lang.model.SourceVersion.*;
* @see ElementScanner6
* @see ElementScanner8
* @see ElementScanner9
* @see ElementScanner14
* @since 1.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.
*
* This code is free software; you can redistribute it and/or modify it
@ -87,6 +87,7 @@ import static javax.lang.model.SourceVersion.*;
* @see ElementScanner6
* @see ElementScanner7
* @see ElementScanner9
* @see ElementScanner14
* @since 1.8
*/
@SupportedSourceVersion(RELEASE_8)

View File

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

View File

@ -31,6 +31,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.LinkedHashSet;
import java.util.Objects;
import javax.lang.model.AnnotatedConstruct;
import javax.lang.model.element.*;
@ -629,4 +630,42 @@ public interface Elements {
* @since 1.8
*/
boolean isFunctionalInterface(TypeElement type);
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This method is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Returns the record component for the given accessor. Returns null if the
* given method is not a record component accessor.
*
* @implSpec The default implementation of this method checks if the element
* enclosing the accessor has kind {@link ElementKind#RECORD RECORD} if that is
* the case, then all the record components on the accessor's enclosing element
* are retrieved by invoking {@link ElementFilter#recordComponentsIn(Iterable)}.
* If the accessor of at least one of the record components retrieved happen to
* be equal to the accessor passed as a parameter to this method, then that
* record component is returned, in any other case {@code null} is returned.
*
* @param accessor the method for which the record component should be found.
* @return the record component, or null if the given method is not an record
* component accessor
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
@SuppressWarnings("preview")
default RecordComponentElement recordComponentFor(ExecutableElement accessor) {
if (accessor.getEnclosingElement().getKind() == ElementKind.RECORD) {
for (RecordComponentElement rec : ElementFilter.recordComponentsIn(accessor.getEnclosingElement().getEnclosedElements())) {
if (Objects.equals(rec.getAccessor(), accessor)) {
return rec;
}
}
}
return null;
}
}

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -73,6 +73,7 @@ import javax.annotation.processing.SupportedSourceVersion;
* @see SimpleAnnotationValueVisitor7
* @see SimpleAnnotationValueVisitor8
* @see SimpleAnnotationValueVisitor9
* @see SimpleAnnotationValueVisitor14
* @since 1.6
*/
@SupportedSourceVersion(RELEASE_6)

View File

@ -64,6 +64,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleAnnotationValueVisitor6
* @see SimpleAnnotationValueVisitor8
* @see SimpleAnnotationValueVisitor9
* @see SimpleAnnotationValueVisitor14
* @since 1.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.
*
* This code is free software; you can redistribute it and/or modify it
@ -64,6 +64,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleAnnotationValueVisitor6
* @see SimpleAnnotationValueVisitor7
* @see SimpleAnnotationValueVisitor8
* @see SimpleAnnotationValueVisitor14
* @since 1.8
*/
@SupportedSourceVersion(RELEASE_8)

View File

@ -66,6 +66,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleAnnotationValueVisitor6
* @see SimpleAnnotationValueVisitor7
* @see SimpleAnnotationValueVisitor8
* @see SimpleAnnotationValueVisitor14
* @since 9
*/
@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.
*
* This code is free software; you can redistribute it and/or modify it
@ -77,6 +77,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleElementVisitor7
* @see SimpleElementVisitor8
* @see SimpleElementVisitor9
* @see SimpleElementVisitor14
* @since 1.6
*/
@SupportedSourceVersion(RELEASE_6)

View File

@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleElementVisitor6
* @see SimpleElementVisitor8
* @see SimpleElementVisitor9
* @see SimpleElementVisitor14
* @since 1.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.
*
* This code is free software; you can redistribute it and/or modify it
@ -69,6 +69,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleElementVisitor6
* @see SimpleElementVisitor7
* @see SimpleElementVisitor9
* @see SimpleElementVisitor14
* @since 1.8
*/
@SupportedSourceVersion(RELEASE_8)

View File

@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleElementVisitor6
* @see SimpleElementVisitor7
* @see SimpleElementVisitor8
* @see SimpleElementVisitor14
* @since 9
* @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.
*
* This code is free software; you can redistribute it and/or modify it
@ -77,6 +77,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleTypeVisitor7
* @see SimpleTypeVisitor8
* @see SimpleTypeVisitor9
* @see SimpleTypeVisitor14
* @since 1.6
*/
@SupportedSourceVersion(RELEASE_6)

View File

@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleTypeVisitor6
* @see SimpleTypeVisitor8
* @see SimpleTypeVisitor9
* @see SimpleTypeVisitor14
* @since 1.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.
*
* This code is free software; you can redistribute it and/or modify it
@ -70,6 +70,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleTypeVisitor6
* @see SimpleTypeVisitor7
* @see SimpleTypeVisitor9
* @see SimpleTypeVisitor14
* @since 1.8
*/
@SupportedSourceVersion(RELEASE_8)

View File

@ -71,6 +71,7 @@ import static javax.lang.model.SourceVersion.*;
* @see SimpleTypeVisitor6
* @see SimpleTypeVisitor7
* @see SimpleTypeVisitor8
* @see SimpleTypeVisitor14
* @since 9
*/
@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.
*
* This code is free software; you can redistribute it and/or modify it
@ -75,6 +75,8 @@ import static javax.lang.model.SourceVersion.*;
*
* @see TypeKindVisitor7
* @see TypeKindVisitor8
* @see TypeKindVisitor9
* @see TypeKindVisitor14
* @since 1.6
*/
@SupportedSourceVersion(RELEASE_6)

View File

@ -71,6 +71,8 @@ import javax.lang.model.SourceVersion;
*
* @see TypeKindVisitor6
* @see TypeKindVisitor8
* @see TypeKindVisitor9
* @see TypeKindVisitor14
* @since 1.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.
*
* This code is free software; you can redistribute it and/or modify it
@ -71,6 +71,8 @@ import static javax.lang.model.SourceVersion.*;
*
* @see TypeKindVisitor6
* @see TypeKindVisitor7
* @see TypeKindVisitor9
* @see TypeKindVisitor14
* @since 1.8
*/
@SupportedSourceVersion(RELEASE_8)

View File

@ -75,6 +75,7 @@ import static javax.lang.model.SourceVersion.*;
* @see TypeKindVisitor6
* @see TypeKindVisitor7
* @see TypeKindVisitor8
* @see TypeKindVisitor14
* @since 9
*/
@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.
*
* This code is free software; you can redistribute it and/or modify it
@ -216,7 +216,7 @@ createThrowableFromJVMTIErrorCode(JNIEnv * jnienv, jvmtiError errorCode) {
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_CLASS_ATTRIBUTE_CHANGED:
throwableClassName = "java/lang/UnsupportedOperationException";
message = "class redefinition failed: attempted to change the class NestHost or NestMembers attribute";
message = "class redefinition failed: attempted to change the class NestHost, NestMembers, or Record attribute";
break;
case JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_MODIFIERS_CHANGED:

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,7 +29,7 @@ import java.util.List;
import javax.lang.model.element.Name;
/**
* A tree node for a class, interface, enum, or annotation
* A tree node for a class, interface, enum, record, or annotation
* type declaration.
*
* For example:
@ -44,6 +44,7 @@ import javax.lang.model.element.Name;
*
* @jls 8.1 Class Declarations
* @jls 8.9 Enum Types
* @jls 8.10 Record Types
* @jls 9.1 Interface Declarations
* @jls 9.6 Annotation Types
*

View File

@ -648,6 +648,22 @@ public interface Tree {
*/
PROVIDES(ProvidesTree.class),
/**
* {@preview Associated with records, a preview feature of the Java language.
*
* This enum constant is associated with <i>records</i>, a preview
* feature of the Java language. Preview features
* may be removed in a future release, or upgraded to permanent
* features of the Java language.}
*
* Used for instances of {@link ClassTree} representing records.
*
* @since 14
*/
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=false)
RECORD(ClassTree.class),
/**
* Used for instances of {@link RequiresTree} representing
* requires directives in a module declaration.

View File

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

View File

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

View File

@ -344,12 +344,35 @@ public class Flags {
*/
public static final long MATCH_BINDING_TO_OUTER = 1L<<60;
/**
* Flag to indicate that a class is a record. The flag is also used to mark fields that are
* part of the state vector of a record and to mark the canonical constructor
*/
public static final long RECORD = 1L<<61; // ClassSymbols, MethodSymbols and VarSymbols
/**
* Flag to mark a record constructor as a compact one
*/
public static final long COMPACT_RECORD_CONSTRUCTOR = 1L<<51; // MethodSymbols only
/**
* Flag to mark a record field that was not initialized in the compact constructor
*/
public static final long UNINITIALIZED_FIELD= 1L<<51; // VarSymbols only
/** Flag is set for compiler-generated record members, it could be appplied to
* accessors and fields
*/
public static final int GENERATED_MEMBER = 1<<24; // MethodSymbols and VarSymbols
/** Modifier masks.
*/
public static final int
AccessFlags = PUBLIC | PROTECTED | PRIVATE,
LocalClassFlags = FINAL | ABSTRACT | STRICTFP | ENUM | SYNTHETIC,
LocalRecordFlags = LocalClassFlags | STATIC,
MemberClassFlags = LocalClassFlags | INTERFACE | AccessFlags,
MemberRecordFlags = MemberClassFlags | STATIC,
ClassFlags = LocalClassFlags | INTERFACE | PUBLIC | ANNOTATION,
InterfaceVarFlags = FINAL | STATIC | PUBLIC,
VarFlags = AccessFlags | FINAL | STATIC |
@ -357,6 +380,8 @@ public class Flags {
ConstructorFlags = AccessFlags,
InterfaceMethodFlags = ABSTRACT | PUBLIC,
MethodFlags = AccessFlags | ABSTRACT | STATIC | NATIVE |
SYNCHRONIZED | FINAL | STRICTFP,
RecordMethodFlags = AccessFlags | ABSTRACT | STATIC |
SYNCHRONIZED | FINAL | STRICTFP;
public static final long
ExtendedStandardFlags = (long)StandardFlags | DEFAULT,
@ -465,7 +490,8 @@ public class Flags {
PREVIEW_API(Flags.PREVIEW_API),
PREVIEW_ESSENTIAL_API(Flags.PREVIEW_ESSENTIAL_API),
MATCH_BINDING(Flags.MATCH_BINDING),
MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER);
MATCH_BINDING_TO_OUTER(Flags.MATCH_BINDING_TO_OUTER),
RECORD(Flags.RECORD);
Flag(long flag) {
this.value = flag;

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

View File

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

View File

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

View File

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

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.
*
* This code is free software; you can redistribute it and/or modify it
@ -255,4 +255,36 @@ public class SymbolMetadata {
private boolean isStarted() {
return attributes != DECL_NOT_STARTED;
}
private List<Attribute.Compound> removeFromCompoundList(List<Attribute.Compound> l, Attribute.Compound compound) {
ListBuffer<Attribute.Compound> lb = new ListBuffer<>();
for (Attribute.Compound c : l) {
if (c != compound) {
lb.add(c);
}
}
return lb.toList();
}
private List<Attribute.TypeCompound> removeFromTypeCompoundList(List<Attribute.TypeCompound> l, Attribute.TypeCompound compound) {
ListBuffer<Attribute.TypeCompound> lb = new ListBuffer<>();
for (Attribute.TypeCompound c : l) {
if (c != compound) {
lb.add(c);
}
}
return lb.toList();
}
public void remove(Attribute.Compound compound) {
if (attributes.contains(compound)) {
attributes = removeFromCompoundList(attributes, compound);
} else if (type_attributes.contains(compound)) {
type_attributes = removeFromTypeCompoundList(type_attributes, (TypeCompound)compound);
} else if (init_type_attributes.contains(compound)) {
init_type_attributes = removeFromTypeCompoundList(init_type_attributes, (TypeCompound)compound);
} else if (clinit_type_attributes.contains(compound)) {
clinit_type_attributes = removeFromTypeCompoundList(clinit_type_attributes, (TypeCompound)compound);
}
}
}

View File

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

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