Class AbstractMappingStrategy<I,​K extends java.lang.Comparable<K>,​C extends ComplexFieldMapEntry<I,​K,​T>,​T>

  • Type Parameters:
    T - Type of object that is being processed.
    C - The type of the internal many-to-one mapping
    I - The initializer type used to build the internal many-to-one mapping
    K - The type of the key used for internal indexing
    All Implemented Interfaces:
    MappingStrategy<T>
    Direct Known Subclasses:
    ColumnPositionMappingStrategy, HeaderNameBaseMappingStrategy

    public abstract class AbstractMappingStrategy<I,​K extends java.lang.Comparable<K>,​C extends ComplexFieldMapEntry<I,​K,​T>,​T>
    extends java.lang.Object
    implements MappingStrategy<T>
    This class collects as many generally useful parts of the implementation of a mapping strategy as possible.

    This mapping strategy knows of the existence of binding annotations, but assumes through getBindingAnnotations() they are not in use.

    Anyone is welcome to use it as a base class for their own mapping strategies.

    Since:
    4.2
    Author:
    Andrew Rucker Jones
    • Field Summary

      Fields 
      Modifier and Type Field Description
      protected java.util.Locale errorLocale
      Locale for error messages.
      protected HeaderIndex headerIndex
      Maintains a bi-directional mapping between column position(s) and header name.
      protected java.lang.Class<? extends T> type
      This is the class of the bean to be manipulated.
    • Method Summary

      All Methods Instance Methods Abstract Methods Concrete Methods 
      Modifier and Type Method Description
      protected abstract K chooseMultivaluedFieldIndexFromHeaderIndex​(int index)
      For BeanField.indexAndSplitMultivaluedField(java.lang.Object, java.lang.Object) it is necessary to determine which index to pass in.
      protected java.util.Map<java.lang.Class<?>,​java.lang.Object> createBean()
      Implementation will return a bean of the type of object being mapped.
      protected CsvConverter determineConverter​(java.lang.reflect.Field field, java.lang.Class<?> elementType, java.lang.String locale, java.lang.String writeLocale, java.lang.Class<? extends AbstractCsvConverter> customConverter)
      Given the information provided, determines the appropriate built-in converter to be passed in to the BeanField being created.
      protected abstract BeanField<T,​K> findField​(int col)
      Gets the field for a given column position.
      abstract java.lang.String findHeader​(int col)
      Gets the name (or position number) of the header for the given column number.
      java.lang.String[] generateHeader​(T bean)
      This method generates a header that can be used for writing beans of the type provided back to a file.
      protected java.util.Set<java.lang.Class<? extends java.lang.annotation.Annotation>> getBindingAnnotations()
      Returns a set of the annotations that are used for binding in this mapping strategy.
      protected abstract FieldMap<I,​K,​? extends C,​T> getFieldMap()
      Returns the FieldMap associated with this mapping strategy.
      java.lang.Class<? extends T> getType()
      Get the class type that the Strategy is mapping.
      void ignoreFields​(org.apache.commons.collections4.MultiValuedMap<java.lang.Class<?>,​java.lang.reflect.Field> fields)
      When processing a bean for reading or writing, ignore the given fields from the given classes completely, including all annotations and requirements.
      protected java.util.Map<java.lang.Class<?>,​java.lang.Object> indexBean​(T bean)
      Creates an index of necessary types according to the mapping strategy and existing instances of (subordinate) beans.
      protected abstract void initializeFieldMap()
      Creates an empty binding-type-specific field map that can be filled in later steps.
      protected BeanField<T,​K> instantiateCustomConverter​(java.lang.Class<? extends AbstractBeanField<T,​K>> converter)
      Attempts to instantiate the class of the custom converter specified.
      protected void loadAnnotatedFieldMap​(org.apache.commons.collections4.ListValuedMap<java.lang.Class<?>,​java.lang.reflect.Field> fields)
      Creates a map of annotated fields in the bean to be processed.
      protected void loadFieldMap()
      Builds a map of columns from the input to fields of the bean type.
      protected com.opencsv.bean.AbstractMappingStrategy.RecursiveType loadRecursiveClasses​(java.lang.Class<?> newType, java.util.Set<java.lang.Class<?>> encounteredTypes)
      Creates a tree of beans embedded in each other.
      protected abstract void loadUnadornedFieldMap​(org.apache.commons.collections4.ListValuedMap<java.lang.Class<?>,​java.lang.reflect.Field> fields)
      Creates a map of fields in the bean to be processed that have no annotations.
      protected java.util.Map<java.lang.Boolean,​org.apache.commons.collections4.ListValuedMap<java.lang.Class<?>,​java.lang.reflect.Field>> partitionFields()
      Partitions all non-synthetic fields of the bean type being processed into annotated and non-annotated fields according to getBindingAnnotations().
      T populateNewBean​(java.lang.String[] line)
      Takes a line of input from a CSV file and creates a bean out of it.
      void setErrorLocale​(java.util.Locale errorLocale)
      Sets the locale for all error messages.
      protected void setFieldValue​(java.util.Map<java.lang.Class<?>,​java.lang.Object> beanTree, java.lang.String value, int column)
      Populates the field corresponding to the column position indicated of the bean passed in according to the rules of the mapping strategy.
      void setType​(java.lang.Class<? extends T> type)
      Sets the class type that is being mapped.
      java.lang.String[] transmuteBean​(T bean)
      Transmutes a bean instance into an array of Strings to be written to a CSV file.
      protected abstract void verifyLineLength​(int numberOfFields)
      Must be called once the length of input for a line/record is known to verify that the line was complete.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • type

        protected java.lang.Class<? extends T> type
        This is the class of the bean to be manipulated.
      • headerIndex

        protected final HeaderIndex headerIndex
        Maintains a bi-directional mapping between column position(s) and header name.
      • errorLocale

        protected java.util.Locale errorLocale
        Locale for error messages.
    • Constructor Detail

      • AbstractMappingStrategy

        public AbstractMappingStrategy()
    • Method Detail

      • getFieldMap

        protected abstract FieldMap<I,​K,​? extends C,​T> getFieldMap()
        Returns the FieldMap associated with this mapping strategy.
        Returns:
        The FieldMap used by this strategy
      • getBindingAnnotations

        protected java.util.Set<java.lang.Class<? extends java.lang.annotation.Annotation>> getBindingAnnotations()
        Returns a set of the annotations that are used for binding in this mapping strategy. The default implementation returns the empty set.
        Returns:
        Annotations of the sort CsvBindByName or CsvBindByPosition that are relevant for binding input fields to bean members in this mapping strategy
        Since:
        5.0
      • loadAnnotatedFieldMap

        protected void loadAnnotatedFieldMap​(org.apache.commons.collections4.ListValuedMap<java.lang.Class<?>,​java.lang.reflect.Field> fields)
        Creates a map of annotated fields in the bean to be processed.

        This method is called by loadFieldMap() when at least one relevant annotation is found on a member variable.

        The default implementation assumes there are no annotations and does nothing.

        Parameters:
        fields - A list of fields annotated with a binding annotation in the bean to be processed
        Since:
        5.0
      • loadUnadornedFieldMap

        protected abstract void loadUnadornedFieldMap​(org.apache.commons.collections4.ListValuedMap<java.lang.Class<?>,​java.lang.reflect.Field> fields)
        Creates a map of fields in the bean to be processed that have no annotations. This method is called by loadFieldMap() when absolutely no annotations that are relevant for this mapping strategy are found in the type of bean being processed.
        Parameters:
        fields - A list of all non-synthetic fields in the bean to be processed
        Since:
        5.0
      • initializeFieldMap

        protected abstract void initializeFieldMap()
        Creates an empty binding-type-specific field map that can be filled in later steps.

        This method may be called multiple times and must erase any state information from previous calls.

        Since:
        5.0
      • findField

        protected abstract BeanField<T,​K> findField​(int col)
        Gets the field for a given column position.
        Parameters:
        col - The column to find the field for
        Returns:
        BeanField containing the field for a given column position, or null if one could not be found
        Throws:
        CsvBadConverterException - If a custom converter for a field cannot be initialized
      • verifyLineLength

        protected abstract void verifyLineLength​(int numberOfFields)
                                          throws CsvRequiredFieldEmptyException
        Must be called once the length of input for a line/record is known to verify that the line was complete. Complete in this context means, no required fields are missing. The issue here is, as long as a column is present but empty, we can check whether the field is required and throw an exception if it is not, but if the data end prematurely, we never have this chance without indication that no more data are on the way. Another validation is that the number of fields must match the number of headers to prevent a data mismatch situation.
        Parameters:
        numberOfFields - The number of fields present in the line of input
        Throws:
        CsvRequiredFieldEmptyException - If a required column is missing
        Since:
        4.0
      • createBean

        protected java.util.Map<java.lang.Class<?>,​java.lang.Object> createBean()
                                                                               throws CsvBeanIntrospectionException,
                                                                                      java.lang.IllegalStateException
        Implementation will return a bean of the type of object being mapped.
        Returns:
        A new instance of the class being mapped.
        Throws:
        CsvBeanIntrospectionException - Thrown on error creating object.
        java.lang.IllegalStateException - If the type of the bean has not been initialized through setType(java.lang.Class)
      • indexBean

        protected java.util.Map<java.lang.Class<?>,​java.lang.Object> indexBean​(T bean)
                                                                              throws java.lang.IllegalAccessException,
                                                                                     java.lang.reflect.InvocationTargetException
        Creates an index of necessary types according to the mapping strategy and existing instances of (subordinate) beans.
        Parameters:
        bean - The root bean to be indexed
        Returns:
        The index from type to instance
        Throws:
        java.lang.IllegalAccessException - If there are problems accessing a subordinate bean
        java.lang.reflect.InvocationTargetException - If there are problems accessing a subordinate bean
        Since:
        5.0
      • findHeader

        public abstract java.lang.String findHeader​(int col)
        Gets the name (or position number) of the header for the given column number. The column numbers are zero-based.
        Parameters:
        col - The column number for which the header is sought
        Returns:
        The name of the header
      • generateHeader

        public java.lang.String[] generateHeader​(T bean)
                                          throws CsvRequiredFieldEmptyException
        This method generates a header that can be used for writing beans of the type provided back to a file.

        The ordering of the headers is determined by the FieldMap in use.

        This method should be called first by all overriding classes to make certain headerIndex is properly initialized.

        Specified by:
        generateHeader in interface MappingStrategy<I>
        Parameters:
        bean - One fully populated bean from which the header can be derived. This is important in the face of joining and splitting. If we have a MultiValuedMap as a field that is the target for a join on reading, that same field must be split into multiple columns on writing. Since the joining is done via regular expressions, it is impossible for opencsv to know what the column names are supposed to be on writing unless this bean includes a fully populated map.
        Returns:
        An array of column names for a header. This may be an empty array if no header should be written, but it must not be null.
        Throws:
        CsvRequiredFieldEmptyException - If a required header is missing while attempting to write. Since every other header is hard-wired through the bean fields and their associated annotations, this can only happen with multi-valued fields.
      • getType

        public java.lang.Class<? extends T> getType()
        Get the class type that the Strategy is mapping.
        Returns:
        Class of the object that this MappingStrategy will create.
      • setType

        public void setType​(java.lang.Class<? extends T> type)
                     throws CsvBadConverterException
        Sets the class type that is being mapped. Also initializes the mapping between column names and bean fields and attempts to create one example bean to be certain there are no fundamental problems with creation.
        Specified by:
        setType in interface MappingStrategy<I>
        Parameters:
        type - Class type.
        Throws:
        CsvBadConverterException - If a field in the bean is annotated with a custom converter that cannot be initialized. If you are not using custom converters that you have written yourself, it should be safe to catch this exception and ignore it.
      • ignoreFields

        public void ignoreFields​(org.apache.commons.collections4.MultiValuedMap<java.lang.Class<?>,​java.lang.reflect.Field> fields)
                          throws java.lang.IllegalArgumentException
        Description copied from interface: MappingStrategy
        When processing a bean for reading or writing, ignore the given fields from the given classes completely, including all annotations and requirements.

        This method has two compelling applications:

        1. If you are not able to modify the source code of the beans you use, or
        2. If you use a mapping strategy without annotations and want to exclude a small number of fields from a bean with a large number of fields.

        Calling this method overwrites the fields passed in from any previous calls. It is legal to call this method before calling MappingStrategy.setType(Class), and it may be more efficient to do so.

        Caution must be exercised with this method when letting opencsv automatically determine the mapping strategy. When a field is ignored, opencsv pretends it does not exist at all. If, for instance, all fields annotated with opencsv binding annotations are ignored, opencsv will automatically switch to HeaderColumnNameMappingStrategy and assume header names exactly match field names.

        An implementation of this interface is not required to implement this method. The default implementation throws UnsupportedOperationException.

        Specified by:
        ignoreFields in interface MappingStrategy<I>
        Parameters:
        fields - All fields to be ignored, mapped from the classes of which they are members. These are the classes as opencsv encounters them, not necessarily the declaring classes if any fields are inherited. May be null.
        Throws:
        java.lang.IllegalArgumentException - If any entry in the map has a null key, a null value, or if the value is not a field in the class represented by the key
        See Also:
        CsvIgnore
      • loadFieldMap

        protected void loadFieldMap()
                             throws CsvBadConverterException
        Builds a map of columns from the input to fields of the bean type.
        Throws:
        CsvBadConverterException - If there is a problem instantiating the custom converter for an annotated field
      • loadRecursiveClasses

        protected com.opencsv.bean.AbstractMappingStrategy.RecursiveType loadRecursiveClasses​(java.lang.Class<?> newType,
                                                                                              java.util.Set<java.lang.Class<?>> encounteredTypes)
        Creates a tree of beans embedded in each other. These are the member variables annotated with CsvRecurse and their associated types. This method is used recursively.
        Parameters:
        newType - The type that is meant to be added to the tree
        encounteredTypes - A set of types already encountered during recursion, as types may not be recursed into more than once.
        Returns:
        A representation of this type and all of the types beneath it in a tree
        Throws:
        CsvRecursionException - If recursion is attempted into a primitive type or a previously encountered type is added again or a member variable annotated with CsvRecurse is also annotated with a binding annotation
      • partitionFields

        protected java.util.Map<java.lang.Boolean,​org.apache.commons.collections4.ListValuedMap<java.lang.Class<?>,​java.lang.reflect.Field>> partitionFields()
        Partitions all non-synthetic fields of the bean type being processed into annotated and non-annotated fields according to getBindingAnnotations().
        Returns:
        A multi-valued map (class to multiple fields in that class) in which all annotated fields are mapped under Boolean.TRUE, and all non-annotated fields are mapped under Boolean.FALSE.
        Since:
        5.0
      • instantiateCustomConverter

        protected BeanField<T,​K> instantiateCustomConverter​(java.lang.Class<? extends AbstractBeanField<T,​K>> converter)
                                                           throws CsvBadConverterException
        Attempts to instantiate the class of the custom converter specified.
        Parameters:
        converter - The class for a custom converter
        Returns:
        The custom converter
        Throws:
        CsvBadConverterException - If the class cannot be instantiated
      • setErrorLocale

        public void setErrorLocale​(java.util.Locale errorLocale)
        Description copied from interface: MappingStrategy
        Sets the locale for all error messages. The default implementation does nothing, as it is expected that most implementations of this interface will not support multiple languages.
        Specified by:
        setErrorLocale in interface MappingStrategy<I>
        Parameters:
        errorLocale - Locale for error messages. If null, the default locale is used.
      • setFieldValue

        protected void setFieldValue​(java.util.Map<java.lang.Class<?>,​java.lang.Object> beanTree,
                                     java.lang.String value,
                                     int column)
                              throws CsvDataTypeMismatchException,
                                     CsvRequiredFieldEmptyException,
                                     CsvConstraintViolationException,
                                     CsvValidationException
        Populates the field corresponding to the column position indicated of the bean passed in according to the rules of the mapping strategy. This method performs conversion on the input string and assigns the result to the proper field in the provided bean.
        Parameters:
        beanTree - Object containing the field to be set.
        value - String containing the value to set the field to.
        column - The column position from the CSV file under which this value was found.
        Throws:
        CsvDataTypeMismatchException - When the result of data conversion returns an object that cannot be assigned to the selected field
        CsvRequiredFieldEmptyException - When a field is mandatory, but there is no input datum in the CSV file
        CsvConstraintViolationException - When the internal structure of data would be violated by the data in the CSV file
        CsvValidationException - If a user-supplied validator determines that the input is invalid
        Since:
        4.2
      • determineConverter

        protected CsvConverter determineConverter​(java.lang.reflect.Field field,
                                                  java.lang.Class<?> elementType,
                                                  java.lang.String locale,
                                                  java.lang.String writeLocale,
                                                  java.lang.Class<? extends AbstractCsvConverter> customConverter)
                                           throws CsvBadConverterException
        Given the information provided, determines the appropriate built-in converter to be passed in to the BeanField being created.
        Parameters:
        field - The field of the bean type in question
        elementType - The type to be generated by the converter (on reading)
        locale - The locale for conversion on reading. May be null or an empty string if a locale is not in use.
        writeLocale - The locale for conversion on writing. May be null or an empty string if a locale is not in use.
        customConverter - An optional custom converter
        Returns:
        The appropriate converter for the necessary conversion
        Throws:
        CsvBadConverterException - If the converter cannot be instantiated
        Since:
        4.2