杰克逊没有为 android.graphics.Bitmap 找到合适的构造函数

Posted

技术标签:

【中文标题】杰克逊没有为 android.graphics.Bitmap 找到合适的构造函数【英文标题】:Jackson no suitable constructor found for android.graphics.Bitmap 【发布时间】:2017-03-30 01:19:21 【问题描述】:

我正在尝试使用 Jackson 序列化我的 Character 对象。 mapper.writeValue 方法调用似乎是成功的,但是当我尝试使用 mapper.readValue 读取值时,我收到以下错误消息:

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of android.graphics.Bitmap: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: java.io.FileReader@9ab6557; line: 1, column: 199] (through reference chain: java.lang.Object[][0]->com.myproj.character.Character["compositeClothes"]->com.myproj.character.clothing.CompositeClothing["clothes"]->java.util.ArrayList[0]->com.myproj.character.clothing.concrete.Hat["bitmap"])

这些是我的课程:

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
@JsonSubTypes(
        @JsonSubTypes.Type(value = Hat.class, name = "hat"),
        @JsonSubTypes.Type(value = Necklace.class, name = "necklace"),
        @JsonSubTypes.Type(value = Shirt.class, name = "shirt")
)
public interface Clothing 
    int getCoolness();

    int getrId();

    Bitmap getBitmap();

我的帽子课:

public class Hat implements Clothing 
    private int rId;
    private int coolness;
    private Bitmap bitmap;

    @JsonCreator
    public Hat(@JsonProperty("coolness") int coolness, @JsonProperty("bitmap") Bitmap bitmap) 
        rId = R.id.hat_image;
        this.coolness = coolness;
        this.bitmap = bitmap;
    

    public int getrId() 
        return rId;
    

    @Override
    public int getCoolness() 
        return coolness;
    

    public Bitmap getBitmap() 
        return bitmap;
    

我的复合服装课:

public class CompositeClothing implements Clothing, Iterable<Clothing> 
    @JsonProperty("coolness")
    private int coolness = 0;
    private List<Clothing> clothes = new ArrayList<>();

    public void add(Clothing clothing) 
        clothes.add(clothing);
    

    public void remove(Clothing clothing) 
        clothes.remove(clothing);
    

    public Clothing getChild(int index) 
        if (index >= 0 && index < clothes.size()) 
            return clothes.get(index);
         else 
            return null;
        
    

    @Override
    public Iterator<Clothing> iterator() 
        return clothes.iterator();
    

    @Override
    public int getCoolness() 
        return coolness;
    

    @Override
    public int getrId() 
        return 0;
    

    @Override
    public Bitmap getBitmap() 
        return null;
    

还有我的角色类:

public class Character implements Observable 
    private static final transient Character instance = new Character();

    @JsonProperty("compositeClothes")
    private CompositeClothing clothes = new CompositeClothing();
    @JsonProperty("compositeHeadFeatures")
    private CompositeHeadFeature headFeatures = new CompositeHeadFeature();

    private transient List<Observer> observers = new ArrayList<>();

    @JsonProperty("skin")
    private Skin skin;

    public void attach(Observer observer) 
        observers.add(observer);
    

    public void notifyAllObservers() 
        for (Observer observer : observers) 
            observer.update();
        
    

    public void setSkin(Skin skin) 
        this.skin = skin;
        notifyAllObservers();
    

    public Skin.Color getSkinColor() 
        return skin.getColor();
    

    public Bitmap getSkinBitmap() 
        return skin.getBitmap();
    

    public boolean hasSkin() 
        return skin != null;
    

    public void addClothing(Clothing clothing) 
        Clothing oldClothing = (Clothing) getSameTypeObjectAlreadyWorn(clothing);

        if (oldClothing != null) 
            clothes.remove(oldClothing);
        

        clothes.add(clothing);
        notifyAllObservers();
    

    public CompositeClothing getClothes() 
        return clothes;
    

    private Object getSameTypeObjectAlreadyWorn(Object newClothing) 
        Class<?> newClass = newClothing.getClass();

        for (Object clothing : clothes) 
            if (clothing.getClass().equals(newClass)) 
                return clothing;
            
        

        return null;
    

    public void removeClothing(Clothing clothing) 
        clothes.remove(clothing);
    

    public void addHeadFeature(HeadFeature headFeature) 
        HeadFeature oldHeadFeature = (HeadFeature) getSameTypeObjectAlreadyWorn(headFeature);

        if (oldHeadFeature != null) 
            headFeatures.remove(oldHeadFeature);
        

        headFeatures.add(headFeature);
        notifyAllObservers();
    

    public void removeHeadFeature(HeadFeature headFeature) 
        headFeatures.remove(headFeature);
    

    public CompositeHeadFeature getHeadFeatures() 
        return headFeatures;
    

    public static Character getInstance() 
        return instance;
    

我用来持久化然后读取数据的代码:

File charactersFile = new File(getFilesDir() + File.separator + "characters.ser");
ObjectMapper mapper = new ObjectMapper()
        .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
        .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);

try (FileWriter fileOut = new FileWriter(charactersFile, false)) 
    List<Character> characters = Arrays.asList(character);
    mapper.writeValue(fileOut, characters);
 catch (IOException e) 
    e.printStackTrace();


Character[] characters = null;
try (FileReader fileIn = new FileReader(charactersFile)) 
    characters = mapper.readValue(fileIn, Character[].class);
 catch (IOException e) 
    e.printStackTrace();

谢谢!

【问题讨论】:

Bitmap 放入 JSON 需要将其转换为某种文本格式(例如 base64)。我建议做其他事情,而不是尝试将位图放在 JSON 中。这些位图来自哪里? 来自我的应用程序附带的资产。也许我可以将我的位图转换为字节 [],或者只使用路径?事情是新的“衣服”将由用户稍后添加到应用程序中,这些将存储在内部存储中,我猜这会使定位它有点困难。 【参考方案1】:

如果您的位图来自资产或资源,则将位图保存为 JSON 是没有意义的。这将浪费 CPU 时间和磁盘空间。相反,在 JSON 中存储一个值,以便您识别要显示的资产或资源。但是,请记住,资源 ID(例如,R.drawable.foo)可能会因应用版本而异,因此这不是图像的良好持久标识符。

【讨论】:

我想我需要将 getAssetManager() + "clothing/..." 路径或 getInternalStorage() + "clothing/..." 路径存储/添加到相应的对象.【参考方案2】:

我的应用程序中有类似的要求,我需要以 JSON 格式存储可绘制数据。我通过只存储它的字符串名称来解决它。例如,如果我有资源R.drawable.testBmp,那么我将它存储在 JSON 中,如下所示:


   ...
   "mydrawable" : "testBmp"

然后在运行时,我会阅读它并转换为可绘制的,如下代码:

JSONObject jsonObj;
...
String bmpName = jsonObj.getString("mydrawable");           
int resId = context.getResources().getIdentifier(bmpName, 
                                    "drawable",
                                    context.getPackageName());
Drawable bmp = ContextCompat.getDrawable(context,resId);

【讨论】:

以上是关于杰克逊没有为 android.graphics.Bitmap 找到合适的构造函数的主要内容,如果未能解决你的问题,请参考以下文章

杰克逊 XML 到 JSON 没有正确格式化列表

Java - 使用杰克逊将 json 转换为复杂对象

迈克尔杰克逊的死因是啥?

杰克逊序列化没有正确处理单引号

杰克逊没有在 JSON 中转义引号

没有默认构造函数的杰克逊第 3 方类