如何使用自定义类加载器反序列化对象?

时间:2019-01-29 12:00:02

标签: java

在一个项目中,我需要使用自定义类加载器来扩展标准类加载器。其主要动机是在运行时扩展类路径。 (有关此问题的解决方案,请参见:https://stackoverflow.com/a/51584718/231397)。

通过...序列化对象

api

工作正常,同时通过以下方式反序列化对象

public class BakingAppWidgetProvider extends AppWidgetProvider implements JsonTask.JsonToBookConverter {

private final String LOG_TAG = this.getClass().getSimpleName();

private Recipe currentRecipe;

//THE API DATA SHOULD BE STORED HERE AFTER IT'S BEEN CONVERTED TO THIS DATATYPE
private RecipeBook book;

private static final String ACTION_UPDATE_CLICK_NEXT = "action.UPDATE_CLICK_NEXT";
private static final String ACTION_UPDATE_CLICK_PREVIOUS = "action.UPDATE_CLICK_PREVIOUS";

public BakingAppWidgetProvider() {
    String jsonString = null;
    ////THE DATA COMES FROM THIS TASK (OWN CLASS IMPLEMENTATION OF ASYNCTASK)
    new JsonTask(jsonString, this).execute();
}

////THIS IS THE METHOD FROM THE INTERFACE THAT IS DECLARED IN THE ASYNCTASK IMPLEMENTATION; IT'S CALLED IN onPostExecuted AND CONVERTS THE JSON TO MY BOOK DATA TYPE
public void convertJson(String jsonString) {

    Gson gson = new Gson();
    String preparedForGson = "{recipes:" + jsonString + "}";
    /// I have access to  'private RecipeBook book; '
    book = gson.fromJson(preparedForGson, RecipeBook.class);

    Log.v(LOG_TAG, "book is ready");
   // WORKS
    Log.v(LOG_TAG, book.toString());


}

public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    Log.v(LOG_TAG, "Widget onUpdate");

    final int N = appWidgetIds.length;
    for (int i = 0; i < N; i++) {


        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.baking_appwidget);
        views.setOnClickPendingIntent(R.id.rightBtn, getPendingSelfIntent(context, ACTION_UPDATE_CLICK_NEXT));

        int appWidgetId = appWidgetIds[i];
        appWidgetManager.updateAppWidget(appWidgetId, views);

    }
}

PendingIntent getPendingSelfIntent(Context context, String action) {
    Intent intent = new Intent(context, getClass());
    intent.setAction(action);
    return PendingIntent.getBroadcast(context, 0, intent, 0);

}

  //PROBLEM IS HERE
@Override
public void onReceive(Context context, Intent intent) {
    super.onReceive(context, intent);
    Log.v(LOG_TAG, "onReceive");
    Log.v(LOG_TAG, intent.getAction());


    // you should simply go back and forth in the recipe collection
    if (ACTION_UPDATE_CLICK_NEXT.equals(intent.getAction())) {
        Log.v(LOG_TAG, "nextClicked");

        //THIS LEADS TO A NULLPOINTEREXEPTION!!!!!
        Log.v(LOG_TAG, book.toString());


    } else if (ACTION_UPDATE_CLICK_PREVIOUS.equals(intent.getAction())) {
        Log.v(LOG_TAG, "prevClicked");

    }

失败,发生ObjectOutputStream out; try { FileOutputStream fos = new FileOutputStream(filename); out = new ObjectOutputStream(fos); out.writeObject(object); } catch(FileNotFoundException e) {} catch (IOException e) { } finally { out.close(); } 异常。原因是调用了标准类加载器,而该类加载器不知道自定义类加载器。

问:使用自定义类加载器反序列化对象的正确方法是什么?

1 个答案:

答案 0 :(得分:3)

(注意:在网上搜索解决方案后,我回答了我自己的问题。人们在网上发现的一些解决方案“几乎是正确的”:不适用于内部类)。

解决方案是扩展ObjectInputStream并覆盖方法resolveClass(ObjectStreamClass) 这可以通过匿名类来完成。然后将Class.forName内的resolveClass与自定义类加载器一起使用。那是

Object object = null;
try {
  FileInputStream fis = new FileInputStream(filename);
  ObjectInputStream in = new ObjectInputStream(fis) {
    @Override
    public Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
      try {
        return Class.forName(desc.getName(), true, customClassLoader);
      } catch (Exception e) { }

      // Fall back (e.g. for primClasses)
      return super.resolveClass(desc);
    }
  };

  object = in.readObject();
}
catch(FileNotFoundException e) {}
catch (ClassNotFoundException e) {}
finally {
  in.close();
}

备注:您可能会找到建议使用的解决方案

customClassLoader.loadClass(desc.getName());

代替

Class.forName(desc.getName(), true, customClassLoader)

尽管这在许多情况下都可行,但可能会有问题。例如,我发现customClassLoader.loadClass(desc.getName())不适用于内部类(可能是由于在解析为p.A.B或p.A $ B的程序包p中,对A类的内部B类的命名存在差异)。另请注意,loadClass不会初始化该类。参见https://stackoverflow.com/a/7099453/231397