001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2025 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 012 * specific language governing permissions and limitations under the License. 013 */ 014package org.microbean.attributes; 015 016import java.lang.constant.ClassDesc; 017import java.lang.constant.DynamicConstantDesc; 018import java.lang.constant.MethodHandleDesc; 019import java.lang.constant.MethodTypeDesc; 020 021import java.util.Objects; 022import java.util.Optional; 023 024import static java.lang.constant.ConstantDescs.BSM_INVOKE; 025import static java.lang.constant.ConstantDescs.CD_Class; 026import static java.lang.constant.DirectMethodHandleDesc.Kind.STATIC; 027 028/** 029 * A {@link Value} whose value is a {@code Class}. 030 * 031 * @param value the value 032 * 033 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 034 */ 035public final record ClassValue(Class<?> value) implements Value<ClassValue> { 036 037 public static final ClassValue CLASS_JAVA_LANG_OBJECT = new ClassValue(Object.class); 038 039 public static final ClassValue CLASS_JAVA_LANG_STRING = new ClassValue(String.class); 040 041 /** 042 * Creates a new {@link ClassValue}. 043 * 044 * @param value the value; must not be {@code null} 045 * 046 * @exception NullPointerException if {@code value} is {@code null} 047 */ 048 public ClassValue { 049 Objects.requireNonNull(value, "value"); 050 } 051 052 @Override // Comparable<ClassValue> 053 public final int compareTo(final ClassValue other) { 054 if (other == null) { 055 return -1; 056 } else if (this.equals(other)) { 057 return 0; 058 } 059 return this.value().getName().compareTo(other.value().getName()); 060 } 061 062 @Override // Constable 063 public final Optional<DynamicConstantDesc<ClassValue>> describeConstable() { 064 final ClassDesc cd = ClassDesc.of(this.getClass().getName()); 065 return 066 Optional.of(DynamicConstantDesc.of(BSM_INVOKE, 067 MethodHandleDesc.ofMethod(STATIC, 068 cd, 069 "of", 070 MethodTypeDesc.of(cd, 071 CD_Class)), 072 this.value().describeConstable().orElseThrow())); 073 } 074 075 @Override // Record 076 public final boolean equals(final Object other) { 077 return 078 other == this || 079 // Follow java.lang.annotation.Annotation requirements. 080 other != null && other.getClass() == this.getClass() && this.value().equals(((ClassValue)other).value()); 081 } 082 083 @Override // Record 084 public final int hashCode() { 085 // Follow java.lang.annotation.Annotation requirements. 086 return this.value().hashCode(); 087 } 088 089 @Override // Record 090 public final String toString() { 091 return this.value().getName(); // binary name 092 } 093 094 /** 095 * Returns a {@link ClassValue} suitable for the supplied arguments. 096 * 097 * @param c a {@code Class}; must not be {@code null} 098 * 099 * @return a non-{@code null} {@link ClassValue} 100 * 101 * @exception NullPointerException if {@code c} is {@code null} 102 */ 103 public static final ClassValue of(final Class<?> c) { 104 return 105 c == Object.class ? CLASS_JAVA_LANG_OBJECT : 106 c == String.class ? CLASS_JAVA_LANG_STRING : 107 new ClassValue(c); 108 } 109 110}