All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.facebook.swift.codec.metadata.ThriftStructMetadataBuilder Maven / Gradle / Ivy

There is a newer version: 0.23.1
Show newest version
/*
 * Copyright (C) 2012 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may obtain
 * a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package com.facebook.swift.codec.metadata;

import com.facebook.swift.codec.ThriftIdlAnnotation;
import com.facebook.swift.codec.ThriftStruct;
import com.facebook.swift.codec.metadata.ThriftStructMetadata.MetadataType;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import javax.annotation.concurrent.NotThreadSafe;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import static com.facebook.swift.codec.ThriftField.Requiredness;
import static com.facebook.swift.codec.metadata.FieldKind.THRIFT_FIELD;

@NotThreadSafe
public class ThriftStructMetadataBuilder
    extends AbstractThriftMetadataBuilder
{
    public ThriftStructMetadataBuilder(ThriftCatalog catalog, Type structType)
    {
        super(catalog, structType);

        // verify the class is public and has the correct annotations
        verifyClass(ThriftStruct.class);

        // finally normalize the field metadata using things like
        normalizeThriftFields(catalog);
    }

    @Override
    protected String extractName()
    {
        ThriftStruct annotation = getStructClass().getAnnotation(ThriftStruct.class);
        if (annotation == null) {
            return getStructClass().getSimpleName();
        }
        else if (!annotation.value().isEmpty()) {
            return annotation.value();
        }
        else {
            return getStructClass().getSimpleName();
        }
    }

    @Override
    protected Map extractStructIdlAnnotations()
    {
        ThriftStruct annotation = getStructClass().getAnnotation(ThriftStruct.class);
        if (annotation == null) {
            return ImmutableMap.of();
        }
        else {
            ImmutableMap.Builder builder = ImmutableMap.builder();
            for (ThriftIdlAnnotation idlAnnotation : annotation.idlAnnotations()) {
                builder.put(idlAnnotation.key(), idlAnnotation.value());
            }
            return builder.build();
        }
    }

    @Override
    protected Class extractBuilderClass()
    {
        ThriftStruct annotation = getStructClass().getAnnotation(ThriftStruct.class);
        if (annotation != null && !annotation.builder().equals(void.class)) {
            return annotation.builder();
        }
        else {
            return null;
        }
    }

    @Override
    protected void validateConstructors()
    {
        if (constructorInjections.size() > 1) {
            metadataErrors.addError("Multiple constructors are annotated with @ThriftConstructor ", constructorInjections);
        }
    }

    @Override
    protected boolean isValidateSetter(Method method)
    {
        return method.getParameterTypes().length >= 1;
    }

    //
    // Build final metadata
    //
    @Override
    public ThriftStructMetadata build()
    {
        // this code assumes that metadata is clean
        metadataErrors.throwIfHasErrors();

        // builder constructor injection
        ThriftMethodInjection builderMethodInjection = buildBuilderConstructorInjections();

        // constructor injection (or factory method for builder)
        ThriftConstructorInjection constructorInjections = buildConstructorInjection();

        // fields injections
        Iterable fieldsMetadata = buildFieldInjections();

        // methods injections
        List methodInjections = buildMethodInjections();

        return new ThriftStructMetadata(
                structName,
                extractStructIdlAnnotations(),
                structType,
                builderType,
                MetadataType.STRUCT,
                Optional.fromNullable(builderMethodInjection),
                ImmutableList.copyOf(documentation),
                ImmutableList.copyOf(fieldsMetadata),
                Optional.of(constructorInjections),
                methodInjections
        );
    }

    private ThriftConstructorInjection buildConstructorInjection()
    {
        return Iterables.getOnlyElement(Lists.transform(constructorInjections, new Function()
        {
            @Override
            public ThriftConstructorInjection apply(ConstructorInjection injection)
            {
                return new ThriftConstructorInjection(injection.getConstructor(), buildParameterInjections(injection.getParameters()));
            }
        }));
    }

    @Override
    protected ThriftFieldMetadata buildField(Collection input)
    {
        short id = -1;
        boolean isLegacyId = false;
        Map idlAnnotations = null;
        String name = null;
        Requiredness requiredness = Requiredness.UNSPECIFIED;
        boolean recursive = false;
        ThriftTypeReference thriftTypeReference = null;

        // process field injections and extractions
        ImmutableList.Builder injections = ImmutableList.builder();
        ThriftExtraction extraction = null;
        for (FieldMetadata fieldMetadata : input) {
            id = fieldMetadata.getId();
            isLegacyId = fieldMetadata.isLegacyId();
            name = fieldMetadata.getName();
            recursive = fieldMetadata.isRecursiveReference();
            requiredness = fieldMetadata.getRequiredness();
            idlAnnotations = fieldMetadata.getIdlAnnotations();
            thriftTypeReference = catalog.getFieldThriftTypeReference(fieldMetadata);

            if (fieldMetadata instanceof FieldInjection) {
                FieldInjection fieldInjection = (FieldInjection) fieldMetadata;
                injections.add(new ThriftFieldInjection(fieldInjection.getId(), fieldInjection.getName(), fieldInjection.getField(), fieldInjection.getType()));
            }
            else if (fieldMetadata instanceof ParameterInjection) {
                ParameterInjection parameterInjection = (ParameterInjection) fieldMetadata;
                injections.add(new ThriftParameterInjection(
                        parameterInjection.getId(),
                        parameterInjection.getName(),
                        parameterInjection.getParameterIndex(),
                        fieldMetadata.getJavaType()
                ));
            }
            else if (fieldMetadata instanceof FieldExtractor) {
                FieldExtractor fieldExtractor = (FieldExtractor) fieldMetadata;
                extraction = new ThriftFieldExtractor(fieldExtractor.getId(), fieldExtractor.getName(), fieldExtractor.getType(), fieldExtractor.getField(), fieldExtractor.getJavaType());
            }
            else if (fieldMetadata instanceof MethodExtractor) {
                MethodExtractor methodExtractor = (MethodExtractor) fieldMetadata;
                extraction = new ThriftMethodExtractor(methodExtractor.getId(), methodExtractor.getName(), methodExtractor.getType(), methodExtractor.getMethod(), methodExtractor.getJavaType());
            }
        }

        // add type coercion
        TypeCoercion coercion = null;
        if (!thriftTypeReference.isRecursive() && thriftTypeReference.get().isCoerced()) {
            coercion = catalog.getDefaultCoercion(thriftTypeReference.get().getJavaType());
        }

        ThriftFieldMetadata thriftFieldMetadata = new ThriftFieldMetadata(
                id,
                isLegacyId,
                recursive,
                requiredness,
                idlAnnotations,
                thriftTypeReference,
                name,
                THRIFT_FIELD,
                injections.build(),
                Optional.absent(),
                Optional.absent(),
                Optional.fromNullable(extraction),
                Optional.fromNullable(coercion)
        );
        return thriftFieldMetadata;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy