001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2026 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.construct.element; 015 016import java.lang.annotation.Annotation; 017 018import java.util.Collection; 019import java.util.List; 020import java.util.Set; 021 022import java.util.concurrent.CopyOnWriteArrayList; 023 024import javax.lang.model.element.AnnotationMirror; 025import javax.lang.model.element.Element; 026import javax.lang.model.element.ElementKind; 027import javax.lang.model.element.ElementVisitor; 028import javax.lang.model.element.Modifier; 029import javax.lang.model.element.Name; 030import javax.lang.model.element.VariableElement; 031 032import javax.lang.model.type.TypeMirror; 033 034import static java.util.Objects.requireNonNull; 035 036import static javax.lang.model.element.ElementKind.LOCAL_VARIABLE; 037 038/** 039 * An <strong>experimental</strong> {@link VariableElement} implementation that is a synthetic representation of a local 040 * variable. 041 * 042 * <p>{@link SyntheticLocalVariableElement} instances may be useful for capturing declaration annotations that really 043 * pertain to type usage. Such scenarios are often found in dependency injection systems.</p> 044 * 045 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 046 */ 047public final class SyntheticLocalVariableElement implements VariableElement { 048 049 private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; 050 051 private final List<AnnotationMirror> annotationMirrors; 052 053 private final Name name; 054 055 private final TypeMirror type; 056 057 /** 058 * Creates a new {@link SyntheticLocalVariableElement}. 059 * 060 * @param type a non-{@code null} {@link TypeMirror} that a hypothetical local variable may bear; as of this writing 061 * no validation is performed on any argument supplied for this parameter 062 * 063 * @exception NullPointerException if {@code type} is {@code null} 064 * 065 * @see #SyntheticLocalVariableElement(Collection, TypeMirror, String) 066 */ 067 public SyntheticLocalVariableElement(final TypeMirror type) { 068 this(List.of(), type, null); 069 } 070 071 /** 072 * Creates a new {@link SyntheticLocalVariableElement}. 073 * 074 * @param type a non-{@code null} {@link TypeMirror} that a hypothetical local variable may bear; as of this writing 075 * no validation is performed on any argument supplied for this parameter 076 * 077 * @param name the name of this {@link SyntheticLocalVariableElement}; may be {@code null} 078 * 079 * @exception NullPointerException if {@code type} is {@code null} 080 * 081 * @see #SyntheticLocalVariableElement(Collection, TypeMirror, String) 082 */ 083 public SyntheticLocalVariableElement(final TypeMirror type, final String name) { 084 this(List.of(), type, name); 085 } 086 087 /** 088 * Creates a new {@link SyntheticLocalVariableElement}. 089 * 090 * @param as a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 091 * 092 * @param type a non-{@code null} {@link TypeMirror} that a hypothetical local variable may bear; as of this writing 093 * no validation is performed on any argument supplied for this parameter 094 * 095 * @exception NullPointerException if {@code as} or {@code type} is {@code null} 096 * 097 * @see #SyntheticLocalVariableElement(Collection, TypeMirror, String) 098 */ 099 public SyntheticLocalVariableElement(final Collection<? extends AnnotationMirror> as, final TypeMirror type) { 100 this(as, type, null); 101 } 102 103 /** 104 * Creates a new {@link SyntheticLocalVariableElement}. 105 * 106 * @param as a non-{@code null} {@link Collection} of {@link AnnotationMirror}s 107 * 108 * @param type a non-{@code null} {@link TypeMirror} that a hypothetical local variable may bear; as of this writing 109 * no validation is performed on any argument supplied for this parameter 110 * 111 * @param name the name of this {@link SyntheticLocalVariableElement}; may be {@code null} 112 * 113 * @exception NullPointerException if {@code as} or {@code type} is {@code null} 114 */ 115 public SyntheticLocalVariableElement(final Collection<? extends AnnotationMirror> as, 116 final TypeMirror type, 117 final String name) { 118 super(); 119 this.annotationMirrors = new CopyOnWriteArrayList<>(as); 120 this.name = new SyntheticName(name == null ? "" : name); 121 this.type = requireNonNull(type, "type"); 122 } 123 124 @Override // VariableElement (Element) 125 public final <R, P> R accept(final ElementVisitor<R, P> v, final P p) { 126 return v.visitVariable(this, p); 127 } 128 129 @Override // VariableElement (Element) 130 public final TypeMirror asType() { 131 return this.type; 132 } 133 134 @Override // VariableElement (Object) 135 public final boolean equals(final Object other) { 136 return this == other || switch (other) { 137 case null -> false; 138 case SyntheticLocalVariableElement her when this.getClass() == her.getClass() -> this.type.equals(her.type) && this.name.contentEquals(her.name); 139 default -> false; 140 }; 141 } 142 143 @Override // VariableElement (AnnotatedConstruct) 144 public final List<AnnotationMirror> getAnnotationMirrors() { 145 return this.annotationMirrors; 146 } 147 148 @Deprecated 149 @Override // VariableElement (AnnotatedConstruct) 150 public final <A extends Annotation> A getAnnotation(final Class<A> annotationType) { 151 return null; // deliberate 152 } 153 154 @Deprecated 155 @Override // VariableElement (AnnotatedConstruct) 156 @SuppressWarnings("unchecked") 157 public final <A extends Annotation> A[] getAnnotationsByType(final Class<A> annotationType) { 158 return (A[])EMPTY_ANNOTATION_ARRAY; // deliberate 159 } 160 161 @Override // VariableElement 162 public final Object getConstantValue() { 163 return null; 164 } 165 166 @Override // VariableElement (Element) 167 public final List<? extends Element> getEnclosedElements() { 168 return List.of(); 169 } 170 171 @Override // VariableElement (Element) 172 public final Element getEnclosingElement() { 173 return null; // deliberate 174 } 175 176 @Override // VariableElement (Element) 177 public final ElementKind getKind() { 178 return LOCAL_VARIABLE; 179 } 180 181 @Override // VariableElement (Element) 182 public final Set<Modifier> getModifiers() { 183 return Set.of(); 184 } 185 186 @Override // VariableElement (Element) 187 public final Name getSimpleName() { 188 return this.name; 189 } 190 191 @Override // Object 192 public final int hashCode() { 193 return this.name.hashCode() ^ this.type.hashCode(); 194 } 195 196}