RecordUtil.java

package tools.jackson.databind.util;

import java.lang.reflect.RecordComponent;
import java.util.Arrays;
import java.util.List;

import tools.jackson.databind.PropertyName;
import tools.jackson.databind.cfg.MapperConfig;
import tools.jackson.databind.introspect.AnnotatedClass;
import tools.jackson.databind.introspect.AnnotatedConstructor;
import tools.jackson.databind.introspect.PotentialCreator;

/**
 * Helper class for finding so-called canonical constructor
 * of Record types.
 */
public class RecordUtil
{
    public static String[] getRecordFieldNames(Class<?> recordType) {
        final RecordComponent[] components = recordType.getRecordComponents();
        if (components == null) {
            // not a record, or no reflective access on native image
            return null;
        }
        return Arrays.stream(components).map(RecordComponent::getName).toArray(String[]::new);
    }

    public static PotentialCreator findCanonicalRecordConstructor(MapperConfig<?> config,
            AnnotatedClass recordClass,
            List<PotentialCreator> constructors)
    {
        final RecordComponent[] components = recordClass.getRawType().getRecordComponents();
        if (components == null) {
            // not a record, or no reflective access on native image
            return null;
        }

        // And then locate the canonical constructor
        final int argCount = components.length;
        // One special case: zero-arg constructor not included in candidate List
        if (argCount == 0) {
            // Bit hacky but has to do: create new PotentialCreator let caller deal
            AnnotatedConstructor defCtor = recordClass.getDefaultConstructor();
            if (defCtor != null) {
                return new PotentialCreator(defCtor, null);
            }
        }

        main_loop:
        for (PotentialCreator ctor : constructors) {
            if (ctor.paramCount() != argCount) {
                continue;
            }
            for (int i = 0; i < argCount; ++i) {
                if (!ctor.creator().getRawParameterType(i).equals(components[i].getType())) {
                    continue main_loop;
                }
            }
            // Found it! One more thing; get implicit Record field names:
            final PropertyName[] implicits = new PropertyName[argCount];
            for (int i = 0; i < argCount; ++i) {
                implicits[i] = PropertyName.construct(components[i].getName());
            }
            return ctor.introspectParamNames(config, implicits);
        }

        throw new IllegalArgumentException("Failed to find the canonical Record constructor of type "
                        +ClassUtil.getTypeDescription(recordClass.getType()));
    }
}