candr.yoclip.option.AbstractFieldOption.java Source code

Java tutorial

Introduction

Here is the source code for candr.yoclip.option.AbstractFieldOption.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 candr.yoclip.option;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.tuple.Pair;

import candr.yoclip.OptionsParseException;
import candr.yoclip.ParserOption;

/**
 * Used by the parser to associate an {@link candr.yoclip.annotation.Option Option} or
 * {@link candr.yoclip.annotation.OptionProperties OptionProperties} annotation with a {@code Field} in a class that
 * contains option parser annotations.
 */
abstract class AbstractFieldOption<T> implements ParserOption<T> {
    /**
     * The field that has an options annotation associated with it.
     */
    private Field field;

    /**
     * Initializes the field descriptor to create an association between the bean {@code Field} and the {@code Option}
     * annotation.
     *
     * @param field The bean field annotated with {@code Option}.
     */
    protected AbstractFieldOption(final Field field) {
        this.field = field;
    }

    /**
     * Get the Java {@code Field} that is annotated with either {@link candr.yoclip.annotation.Option Option} or
     * {@link candr.yoclip.annotation.OptionProperties}.
     *
     * @return the Java {@code Field} that has an option annotation associated with it.
     */
    public Field getField() {
        return field;
    }

    /**
     * Get the {@code Class} object that identifies the declared type for the {@code Field} object.
     *
     * @return the {@code Class} that identifies the declared type for the {@code Field}.
     */
    public Class<?> getType() {
        return getField().getType();
    }

    /**
     * The {@code Class} object representing the class or interface that declares the {@code Field}.
     *
     * @return the {@code Class} that declares the {@code Field}.
     */
    @Override
    public Class<?> getDeclaringClass() {
        return getField().getDeclaringClass();
    }

    /**
     * The default unique id for a {@code Field} is the name of the field.
     *
     * @return the name of the field.
     */
    @Override
    public String getUniqueId() {
        return getField().getName();
    }

    /**
     * Used to flag the option as requesting help.
     *
     * @return {@code true} if the option is help related, {@code false} otherwise.
     */
    @Override
    public boolean isHelp() {

        return false;
    }

    /**
     * Indicates the field is annotated with a {@link candr.yoclip.annotation.OptionProperties OptionProperties} annotation.
     *
     * @return {@code true} if the annotation is {@code OptionProperties}, {@code false} otherwise.
     */
    @Override
    public boolean isProperties() {

        return false;
    }

    /**
     * Indicates the field is annotated with a {@link candr.yoclip.annotation.Arguments Arguments} annotation.
     *
     * @return {@code true} if the annotation is {@code Arguments}, {@code false} otherwise.
     */
    @Override
    public boolean isArguments() {

        return false;
    }

    /**
     * Indicates when an option is used a value must also be included.
     *
     * @return {@code true} is a value is required, {@code false} otherwise.
     */
    @Override
    public boolean hasValue() {

        return false;
    }

    @Override
    public List<Pair<String, String>> getPropertyDescriptions() {
        return Collections.emptyList();
    }

    protected void set(final T bean, final Value<T> value) {

        final Field field = getField();

        boolean resetFieldAccessibility = false;
        try {

            if (!field.isAccessible()) {
                field.setAccessible(true);
                resetFieldAccessibility = true;
            }

            value.set(bean, field);

        } catch (Exception e) {
            if (e instanceof OptionsParseException) {
                throw (OptionsParseException) e;
            }
            throw new OptionsParseException("Error setting field " + getUniqueId(), e);

        } finally {
            if (resetFieldAccessibility) {
                field.setAccessible(false);
            }
        }
    }

    @Override
    public String toString() {
        return getUniqueId();
    }

    /**
     * Used internally to set a field value. Callers use the interface similar to a poor mans closure. The setters
     * framework ensures a normally inaccessible field is settable before calling the {@link Value#set set} method.
     *
     * @param <T> The bean type that will be updated.
     */
    public interface Value<T> {

        /**
         * Called by the framework when a value should be set into a field of a bean object.
         *
         * @param bean  The object whose field will be set.
         * @param field The field in the object that will be set.
         * @throws IllegalAccessException This can be called if the field has been marked final.
         */
        void set(T bean, Field field) throws IllegalAccessException;
    }

}