【问题标题】:Enforce compile type safety with TypeSafeMap使用 TypeSafeMap 强制编译类型安全
【发布时间】:2021-04-20 23:23:52
【问题描述】:

问题陈述:我们正在构建一个以 TypeSafeMap 作为响应的库。 TypeSafeMap 是一个可以容纳任何类型对象的映射。 现在,客户端将访问 typesafemap。我们正在尝试强制执行某种程度的编译类型安全。下面是代码和更多解释。

响应结构:

public Class Response {
    private TypeSafeMap t;
    
    public TypeSafeMap getMap() { return t; }
}

//类型安全映射

public class TypeSafeMap 
{
    private final static Map<String, Object> map = new HashMap<>();
    
    public static <T> T put(String key, T value) {
        if (null != key) {
            return (T) map.put(key, value);
        }
        return (T) map;
    }

    @SuppressWarnings("unchecked")
    public static <T> T get(PartyEnums partyEnum)
    {       
        return (T) map.get(partyEnum.PARTY.name());
    }

}

//我们暴露给客户端获取属性和对应字段类型的枚举

public enum PartyEnums
{   
    PARTY("party", new ArrayList<Party>().getClass()); 
    
    private final String name;
    private final Class<?> clzz; //this is the type client should access as field type

    PartyEnums(String name,Class<?> clzz) 
    {
        this.name = name;
        this.clzz=clzz;
    }
    
    public Class<?> getClzz()
    {
        return clzz;
    }
    
    @SuppressWarnings("unchecked")
    public <T> T getInstance()
    {
        T ins = null;
        try {
            ins = (T) getClzz().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return ins;
    }
}

//客户端调用

    public class ClientCall {
        Object obj = TypeSafeMap.get(PartyEnums.PARTY); //No error. 
        String str = TypeSafeMap.get(PartyEnums.PARTY); //No error. 
But we want enforce some level of compile type safety as the field type "str" and TypeSafeMap.get() type do not match. 
How can we enforce compile type safety?
     
       List<Party> party = TypeSafeMap.get(PartyEnums.PARTY);// OK.
    }

【问题讨论】:

    标签: java spring-boot generics collections enums


    【解决方案1】:

    TL;DR

    这不能使用当前形式的enum 来完成。 有一个 JEP 301: Enhanced Enums 可以解决同样的问题,但它已被撤回。


    强制类型安全的唯一选择(当前)是使用带有预定义类型常量的final 类来模拟enum。 我会想象它是这样的:

    public final class Key<V> {
        public static final Key<List<Party>> PARTY_LIST = new Key<>("party list");
        public static final Key<Map<Integer, String>> PARTY_MAP = new Key<>("party map");
        public static final Key<String> SOME_STRING = new Key<>("party string");
    
        private final String name;
        
        private Key(String name) {
            this.name = name;
        }
        
        public String getName() {
            return name;
        }
    }
    

    现在我们已经准备好通过修改&lt;T&gt; T put(String key, T value)(即使“枚举方法”在理论上是可能的)和&lt;T&gt; T get(PartyEnums partyEnum) 这样的方式来使您的TypeSafeMap 真正类型安全:

    public static class TypeSafeMap {
        private final static Map<String, Object> MAP = new HashMap<>();
    
        @SuppressWarnings("unchecked")
        public static <T> T put(Key<T> key, T value) {
            if (null != key) {
                return (T) MAP.put(key.getName(), value);
            }
            
            return value;
        }
    
        @SuppressWarnings("unchecked")
        public static <T> T get(Key<T> key) {
            return (T) MAP.get(key.getName());
        }
    }
    

    我仍然看到至少 2 个可能的问题:

    1. 多个常量可以共享相同的name,因此一旦使用就会有效地相互覆盖(例如,可以使用enum而不是String来解决)
    2. put(Key&lt;T&gt; key, T value) 将输入 value 传递回来,即使是 null 键(在我看来)是故障安全的,但会误导调用者(他们可能认为“存储”操作以某种方式成功。

    但是,鉴于上述实现的弱点仍然符合您的初衷,因此:

    这些情况会通过:

        map.put(Key.JUST_STRING, "just string");
        map.put(Key.PARTY_LIST, Arrays.asList(new Party()));
               ...
        Object resultAsObject = map.get(Key.PARTY_LIST);
        List<Party> resultAsList = map.get(Key.PARTY_LIST);
        String resultString = map.get(Key.JUST_STRING);
    

    但是这些失败并出现编译时错误:

        map.put(Key.PARTY_LIST, Arrays.asList(new String()));
               ...
        String stringFromList = map.get(Key.PARTY_LIST);
    

    请注意,Object resultAsObject = map.get(&lt;ANYTHING&gt;) 将始终成功,因为我们可以将任何返回值(包括空值)表示为 Object 变量

    【讨论】:

      猜你喜欢
      • 2013-11-05
      • 2018-08-26
      • 1970-01-01
      • 2017-01-17
      • 2012-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多