AnnotatedConstructor.java
package tools.jackson.databind.introspect;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.Objects;
import tools.jackson.databind.JavaType;
import tools.jackson.databind.util.ClassUtil;
import static java.lang.invoke.MethodType.methodType;
public final class AnnotatedConstructor
extends AnnotatedWithParams
{
protected final Constructor<?> _constructor;
/**
* Lazily resolved invocation handles, one per arity we support;
* {@code volatile} so a racy first use is safely published (duplicate
* resolution is harmless, handles are equivalent).
*/
protected volatile MethodHandle _invokerNullary;
protected volatile MethodHandle _invokerUnary;
protected volatile MethodHandle _invokerFixedArity;
// // Simple lazy-caching:
/**
* Lazily resolved raw parameter types; {@code volatile} to ensure safe
* publication of the array contents (racy re-resolution is harmless).
*/
protected volatile Class<?>[] _paramClasses;
/*
/**********************************************************************
/* Life-cycle
/**********************************************************************
*/
public AnnotatedConstructor(TypeResolutionContext ctxt, Constructor<?> constructor,
AnnotationMap classAnn, AnnotationMap[] paramAnn)
{
super(ctxt, classAnn, paramAnn);
_constructor = Objects.requireNonNull(constructor);
}
@Override
public AnnotatedConstructor withAnnotations(AnnotationMap ann) {
return new AnnotatedConstructor(_typeContext, _constructor, ann, _paramAnnotations);
}
/*
/**********************************************************************
/* Annotated impl
/**********************************************************************
*/
@Override
public Constructor<?> getAnnotated() { return _constructor; }
@Override
public int getModifiers() { return _constructor.getModifiers(); }
@Override
public String getName() { return _constructor.getName(); }
@Override
public JavaType getType() {
return _typeContext.resolveType(getRawType());
}
@Override
public Class<?> getRawType() {
return _constructor.getDeclaringClass();
}
/*
/**********************************************************************
/* Extended API
/**********************************************************************
*/
@Override
public int getParameterCount() {
return _constructor.getParameterCount();
}
@Override
public Class<?> getRawParameterType(int index)
{
Class<?>[] types = _paramClasses;
if (types == null) {
types = _constructor.getParameterTypes();
_paramClasses = types;
}
return (index >= types.length) ? null : types[index];
}
@Override
public JavaType getParameterType(int index) {
Type[] types = _constructor.getGenericParameterTypes();
if (index >= types.length) {
return null;
}
return _typeContext.resolveType(types[index]);
}
@Override
public Parameter[] getNativeParameters() {
return _constructor.getParameters();
}
@Override
public final Object call() throws Exception {
try {
return invokerNullary().invokeExact();
} catch (Throwable e) {
throw ClassUtil.sneakyThrow(e);
}
}
@Override
public final Object call(Object[] args) throws Exception {
try {
return invokerFixedArity().invokeWithArguments(args);
} catch (Throwable e) {
throw ClassUtil.sneakyThrow(e);
}
}
@Override
public final Object call1(Object arg) throws Exception {
try {
return invokerUnary().invokeExact(arg);
} catch (Throwable e) {
throw ClassUtil.sneakyThrow(e);
}
}
private MethodHandle invokerNullary() throws IllegalAccessException {
MethodHandle h = _invokerNullary;
if (h == null) {
h = unreflect().asType(methodType(Object.class));
_invokerNullary = h;
}
return h;
}
private MethodHandle invokerUnary() throws IllegalAccessException {
MethodHandle h = _invokerUnary;
if (h == null) {
h = unreflect().asType(methodType(Object.class, Object.class));
_invokerUnary = h;
}
return h;
}
private MethodHandle invokerFixedArity() throws IllegalAccessException {
MethodHandle h = _invokerFixedArity;
if (h == null) {
h = unreflect().asFixedArity();
_invokerFixedArity = h;
}
return h;
}
/**
* Note: caller is expected to have called {@code ClassUtil.checkAndFixAccess()}
* already; access checks are suppressed for an accessible {@link Constructor}.
*/
private MethodHandle unreflect() throws IllegalAccessException {
return MethodHandles.lookup().unreflectConstructor(_constructor);
}
/*
/**********************************************************************
/* AnnotatedMember impl
/**********************************************************************
*/
@Override
public Class<?> getDeclaringClass() { return _constructor.getDeclaringClass(); }
@Override
public Member getMember() { return _constructor; }
@Override
public void setValue(Object pojo, Object value)
throws UnsupportedOperationException
{
throw new UnsupportedOperationException("Cannot call setValue() on constructor of "
+getDeclaringClass().getName());
}
@Override
public Object getValue(Object pojo)
throws UnsupportedOperationException
{
throw new UnsupportedOperationException("Cannot call getValue() on constructor of "
+getDeclaringClass().getName());
}
/*
/**********************************************************************
/* Extended API, specific annotations
/**********************************************************************
*/
@Override
public String toString() {
final int argCount = _constructor.getParameterCount();
return "[constructor for %s (%d arg%s), annotations: %s".formatted(
ClassUtil.nameOf(_constructor.getDeclaringClass()), argCount,
(argCount == 1) ? "" : "s", _annotations);
}
@Override
public int hashCode() {
// _constructor can be null for special case of JDK serialization so:
return Objects.hashCode(_constructor);
}
@Override
public boolean equals(Object o) {
if (o == this) return true;
if (!ClassUtil.hasClass(o, getClass())) {
return false;
}
AnnotatedConstructor other = (AnnotatedConstructor) o;
return Objects.equals(_constructor, other._constructor);
}
}