java.lang.constant.ClassDesc and TypeDescriptor for hidden class??

Mandy Chung mandy.chung at oracle.com
Fri Apr 3 18:45:44 UTC 2020



On 4/2/20 10:03 PM, John Rose wrote:
> On Apr 2, 2020, at 11:34 AM, Brian Goetz <brian.goetz at oracle.com> wrote:
>> Mandy reminded me that descriptorString() is specified to return a JLS 4.2.3 field descriptor, and so (c) would violate that spec.  I think this tilts the table away from (c), even though this string is arguably useful (though not clear to whom.)
>>
> Here’s a compromise that almost makes sense on its own:
>
> (d) return the field descriptor string for the hidden class,
> minus the “.X” suffix, appropriately wrapped.
>
> First of all, it’s a valid descriptor.  (Though probably not
> resolvable to a class, still its valid.)  Second, it’s arguably
> how the HC’s descriptor *would* be spelled as a field
> descriptor, if it could.  The CONSTANT_Class entry of
> the original ClassInfo.this_class of the HC has that
> class name, sans added “.X”.
>
> But, I think the best compromise is to admit that, just
> as Class::getName returns an intentionally invalid
> though suggestive class name (rather than null or an
> exception), so Class::descriptorString should return
> the intentionally invalid though suggestive field
> descriptor which is regularly derived from said
> Class::getName.  This provides consistency in
> string-valued outputs; in the absence of an argument
> why their treatment should be inconsistent,
> consistency is less confusing and should win.

This give consistency in the type descriptor returned by 
Class::descriptorString for all classes.

However, inconsistency among the factory methods that produce ClassDesc:

    ClassDesc.ofDescriptor(HC.descriptorString()) - returns a ClassDesc
    ClassDesc.ofDescriptor(HC.getName()) - IAE thrown
    ClassDesc.of(HC.getPackageName(), HC.getSimpleName()) - IAE thrown
    Class::describeConstable - returns an empty optional.

(I am not close to java.lang.constant and the above calls may not be 
expected.)

We should also consider MethodType.  One can create a MethodType with a 
hidden class as a parameter type or return type via the factory 
methods.  In practice no one would need to create such a MethodType as a 
hidden class can't be resolved by name.   If MT(HC) is used to lookup a 
method handle, NoSuchMethodException will be thrown.

If MT(HC).toMethodDescriptorString() and MT(HC)::descriptorString drop 
`.X` suffix, the return descriptor is a valid method descriptor
     MT(HC).descriptorString() - returns "(La/b/C;)V"
     MT(HC).toMethodDescriptorString() - returns "(La/b/C;)V"
     MethodType.fromMethodDescriptorString(MT(HC).descriptorString(), 
loader) - if the loader happens to find class "a.b.C", it will produce a 
MethodType with a.b.C as its return type.
     MT(HC).describeConstable() - returns an empty optional

I'm starting to think throwing a TypeDescriptorNotPresentException would 
be consistent all these relevant APIs.

> The validity checking in the constructor of
> ReferenceClassDescImpl already ensures that such
> a HC descriptor string cannot be mistaken for a
> well-formed field descriptor, since it excludes dots “.”
> in the input.  I think *that* is the right place to
> put the error check, and it’s no accident (this time)
> that the prototype code behaves this way, because
> complicating the spec. with extra validity checks
> would also require more validity checks for the
> affected method (Class::descriptorString).
>
> Under this theory, the code needs one more validity
> check:
>
>      @Override
>      public Optional<ClassDesc> describeConstable() {
>     +     if (isHidden()) return Optional.empty();
>          return Optional.of(ClassDesc.ofDescriptor(descriptorString()));
>      }
>
> If that validity check is missing, then ClassDesc.of would
> throw (in the constructor referred to above), violating
> the convention 0f using Optional.empty().

Yes, that validity check is in needed and in my local patch.

Mandy


More information about the valhalla-dev mailing list