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

io.yupiik.batch.runtime.component.mapping.Mapping Maven / Gradle / Ivy

There is a newer version: 1.0.6
Show newest version
/*
 * Copyright (c) 2021 - Yupiik SAS - https://www.yupiik.com
 * 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 io.yupiik.batch.runtime.component.mapping;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static java.util.stream.Collectors.toList;

/**
 * Enables to define a mapping between an input record and output record.
 */
@Target(TYPE)
@Retention(RUNTIME)
public @interface Mapping {
    /**
     * @return expected input type.
     */
    Class from() default Object.class;

    /**
     * @return expected output type.
     */
    Class to();

    /**
     * IMPORTANT: no implicit mapping, can lead to errors too easily.
     *
     * @return how properties are mapped from the input to the output.
     */
    Property[] properties() default {};

    /**
     * @return list of defined mapping tables.
     */
    MappingTable[] tables() default {};

    /**
     * @return a short description of this mapper.
     */
    String documentation() default "";

    /**
     * @return true to not include this mapper in the documentation.
     */
    boolean enableInDocumentation() default true;

    class ReversedTable {
        private final Collection> underlying;

        public ReversedTable(final Collection> underlying) {
            this.underlying = underlying;
        }

        public List get(final String key) {
            return underlying.stream().filter(it -> it.getValue().equals(key)).map(Map.Entry::getKey).collect(toList());
        }
    }

    @Target(PARAMETER)
    @Retention(RUNTIME)
    @interface Table {
        /**
         * Enables to inject in a custom mapper the map of string/string from the annotation.
         * Note that you can also inject a {@code ReversedTable} if you want a way to reverse the table.
         *
         * @return a mapping table name.
         */
        String value();
    }

    @Target(TYPE)
    @Retention(RUNTIME)
    @interface MappingTable {
        String name();

        Entry[] entries();
    }

    @Target(TYPE)
    @Retention(RUNTIME)
    @interface Entry {
        String input();

        String output();
    }

    @Target(TYPE)
    @Retention(RUNTIME)
    @interface Property {
        PropertyType type() default PropertyType.MAPPED;

        String from() default "";

        String to();

        String value() default "";

        OnTableMappingLookupFailure onMissedTableLookup() default OnTableMappingLookupFailure.FAIL;
    }

    enum OnTableMappingLookupFailure {
        /**
         * Set null.
         */
        NULL,
        /**
         * Keep incoming value.
         */
        FORWARD,
        /**
         * Throw an exception.
         */
        FAIL
    }

    /**
     * Enables to define a custom mapping.
     */
    @Target(METHOD)
    @Retention(RUNTIME)
    @interface Custom {
        /**
         * Name of the target attribute.
         * If empty, name will match the method name.
         *
         * @return the name of the target attribute.
         */
        String to() default "";

        /**
         * Explains the mapping rule implemented in java.
         *
         * @return the description of this field mapping.
         */
        String description();
    }

    enum PropertyType {
        /**
         * Will copy {@code from} property value from the input to {@code to} property in the output.
         */
        MAPPED {
            @Override
            public void doValidate(final Property property) {
                if (property.from().isEmpty()) {
                    throw new IllegalArgumentException("You can't use @Property(type=MAPPED) without specifying from");
                }
            }
        },

        /**
         * Will set {@code value} property to {@code to} property in the output.
         */
        CONSTANT {
            @Override
            public void doValidate(final Property property) {
                if (property.value().isEmpty()) {
                    throw new IllegalArgumentException("You can't use @Property(type=CONSTANT) without specifying value");
                }
            }
        },

        /**
         * Will lookup the output ({@code to}) value in the table mapping reference by {@code value} using as key the string value of the {@code from} parameter.
         * If {@code failIfMissingEntry} is true, it throws an exception when the mapping is incomplete.
         */
        TABLE_MAPPING {
            @Override
            public void doValidate(final Property property) {
                if (property.value().isEmpty()) {
                    throw new IllegalArgumentException("You can't use @Property(type=TABLE_MAPPING) without specifying value");
                }
            }
        };

        protected abstract void doValidate(Property property);

        public void validate(final Property property) {
            doValidate(property);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy