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

com.dyuproject.protostuff.EnumMapping Maven / Gradle / Ivy

The newest version!
//========================================================================
//Copyright 2023 David Yu
//------------------------------------------------------------------------
//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.dyuproject.protostuff;

import java.lang.reflect.Field;
import java.util.HashMap;

/**
 * Metadata that is (re)used for enum serialization.
 *
 * @author David Yu
 * @created Apr 26, 2023
 */
public final class EnumMapping
{
    public static > EnumMapping createFrom(Class clazz, T[] values)
    {
        return getFrom(clazz, values);
    }
    
    public static EnumMapping getOrCreateFrom(Class clazz)
    {
        return getFrom(clazz, null);
    }
    
    @SuppressWarnings({ "unchecked" })
    private static EnumMapping getFrom(final Class clazz, final Enum[] values)
    {
        final Class> enumClass = (Class>)clazz;
        
        final Enum[] constants = values != null ? values : enumClass.getEnumConstants();
        Enum instance = constants[0];
        Field field = null;
        EnumMapping mapping = null;
        if (values == null && EnumLite.class.isAssignableFrom(instance.getClass()))
        {
            try
            {
                field = enumClass.getDeclaredField("$MAPPING");
                mapping = (EnumMapping)field.get(null);
            }
            catch (Exception e)
            {
                // noop
            }
            if (mapping != null)
                return mapping;
        }
        try
        {
            field = enumClass.getField(instance.name());
        }
        catch (NoSuchFieldException e)
        {
            throw new RuntimeException(e);
        }
         
        if (!field.isAnnotationPresent(Tag.class))
            return null;
        
        final HashMap numberIdxMap = new HashMap();
        final int[] numbers = new int[constants.length];
        final HashMap nameIdxMap = new HashMap();
        final String[] names = new String[constants.length];
        
        Integer tmp;
        int fieldNumber;
        String name;
        for (int i = 0, idx = i;; idx = i)
        {
            Tag annotation = field.getAnnotation(Tag.class);
            fieldNumber = annotation.value();
            name = annotation.alias();
            if (name == null || name.isEmpty())
                name = instance.name();
            
            // support multiple name aliasing with the same number
            tmp = fieldNumber;
            if (numberIdxMap.containsKey(tmp))
                idx = numberIdxMap.get(tmp).intValue();
            else
                numberIdxMap.put(fieldNumber, i);
            
            if (null != (tmp = nameIdxMap.put(name, idx)))
            {
                throw new IllegalStateException(constants[tmp.intValue()] + " and " +
                        constants[i] + " cannot have the same alias/name.");
            }
            
            numbers[i] = fieldNumber;
            names[i] = i == idx ? name : names[idx];
            
            if (constants.length == ++i)
                break;
            
            instance = constants[i];
            try
            {
                field = enumClass.getField(instance.name());
            }
            catch (NoSuchFieldException e)
            {
                throw new RuntimeException(e);
            }
            if (!field.isAnnotationPresent(Tag.class))
                throw new RuntimeException("Missing @Tag annotation: " + field);
        }
        
        return new EnumMapping(numberIdxMap, numbers, nameIdxMap, names);
    }
    public final HashMap numberIdxMap;
    public final int[] numbers;
    public final HashMap nameIdxMap;
    public final String[] names;
    
    EnumMapping(HashMap numberIdxMap, int[] numbers,
            HashMap nameIdxMap, String[] names)
    {
        this.numberIdxMap = numberIdxMap;
        this.numbers = numbers;
        this.nameIdxMap = nameIdxMap;
        this.names = names;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy