objectinputstream.readobject中的illegalargumentexception

cgh8pdjw  于 2021-07-03  发布在  Java
关注(0)|答案(1)|浏览(345)

我有一个android应用程序,它显示出奇怪的行为。我有一个从文件反序列化对象的方法。下面是我使用的代码:

  1. public static Object readData(Context context, String fileName)
  2. {
  3. synchronized (context) {
  4. ObjectInputStream input = null;
  5. Object object = null;
  6. if (fileExists(context, fileName)) {
  7. try {
  8. input = new ObjectInputStream(context.openFileInput(fileName));
  9. object = input.readObject();
  10. Log.v(Constant.TAG, "Writable object has been loaded from file "+fileName);
  11. } catch (IOException e) {
  12. Log.e(Constant.TAG, e.getMessage(), e);
  13. } catch (ClassNotFoundException e) {
  14. Log.e(Constant.TAG, e.getMessage(), e);
  15. } finally {
  16. try {
  17. if (input != null)
  18. input.close();
  19. } catch (IOException e) {
  20. Log.e(Constant.TAG, e.getMessage(), e);
  21. }
  22. }
  23. }
  24. return object;
  25. }
  26. }

通常情况下,它工作得很好,但当有人最小化我的应用程序,并在一段时间后重新打开,它崩溃。从事故报告中我发现 IllegalArgumentException 在代码上方的下行中

  1. object = input.readObject();

我查阅了 ObjectInputStream.readObject 但它没有说明在什么情况下它可以扔 IllegalArgumentException .
这只发生在用户从后台带来应用程序时。它在应用程序启动时工作得非常好(我所说的启动是指应用程序没有运行,甚至在后台也没有运行)。
附:有一些车祸报告显示 ClassCastException 在同一行,这是更奇怪的,因为我不是演员,只是阅读成一个 Object .
更新
堆栈跟踪

  1. java.lang.RuntimeException:
  2. at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2423)
  3. at android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2483)
  4. at android.app.ActivityThread.access$900 (ActivityThread.java:153)
  5. at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1349)
  6. at android.os.Handler.dispatchMessage (Handler.java:102)
  7. at android.os.Looper.loop (Looper.java:148)
  8. at android.app.ActivityThread.main (ActivityThread.java:5441)
  9. at java.lang.reflect.Method.invoke (Native Method)
  10. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:738)
  11. at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:628)
  12. Caused by: java.lang.IllegalArgumentException:
  13. at java.lang.reflect.Field.set (Native Method)
  14. at java.io.ObjectInputStream.readFieldValues (ObjectInputStream.java:1127)
  15. at java.io.ObjectInputStream.defaultReadObject (ObjectInputStream.java:454)
  16. at java.io.ObjectInputStream.readObjectForClass (ObjectInputStream.java:1345)
  17. at java.io.ObjectInputStream.readHierarchy (ObjectInputStream.java:1242)
  18. at java.io.ObjectInputStream.readNewObject (ObjectInputStream.java:1835)
  19. at java.io.ObjectInputStream.readNonPrimitiveContent (ObjectInputStream.java:761)
  20. at java.io.ObjectInputStream.readObject (ObjectInputStream.java:1983)
  21. at java.io.ObjectInputStream.readObject (ObjectInputStream.java:1940)
  22. at com.pixyfisocial.pixyfi.util.IOUtil.readData (IOUtil.java:245)
  23. at com.pixyfisocial.Login.getLoggedInUserInfoFromCache (Login.java:313)
  24. at com.pixyfisocial.Login.startApp (Login.java:124)
  25. at com.pixyfisocial.Login.onCreate (Login.java:98)
  26. at android.app.Activity.performCreate (Activity.java:6303)
  27. at android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1108)
  28. at android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2376)
wnavrhmk

wnavrhmk1#

对源代码的粗略检查表明 IllegalArgumentException 通常被扔进去 ObjectInputStream 当序列化对象表示与读取类所期望的不匹配时。例如,您可能有不兼容的自定义项 readObject 以及 writeObject 方法。或者您可能对对象表示进行了二进制不兼容的更改,而没有更改硬编码 serialVersionUID 数字或实现自定义方法来处理此问题2。
你的指纹里会有更多线索。。。在源代码中 ObjectInputStream .
这个 ClassCastException 这可能是另一种表现。
1-导致语义不兼容的变化是另一回事。他们不会导致 IllegalArgumentException 但是你还是应该做点什么。
2-如果您想处理不兼容,那么您可能不想更改 serialVerionUID . 如果您这样做了,那么您将需要对类加载和类的多个版本做一些“聪明的事情”。但另一方面,如果您的代码需要处理具有相同属性的多个表示形式 serialVersionUID ,表示版本必须可以从表示本身推断出来。这需要计划。
后续行动
我获取了你的stacktrace,并尝试将其与android源代码进行匹配https://android.googlesource.com
行号不完全匹配,但我认为问题发生在下面的方法中。特别是我标注的“这里”。根据javadoc for field.set:
如果指定的对象参数不是声明基础字段的类或接口的示例,则该方法将抛出illegalargumentexception。
如果基础字段是基元类型,则尝试展开转换以将新值转换为基元类型的值。如果此尝试失败,该方法将抛出illegalargumentexception。
如果在可能的展开之后,新值无法通过标识或加宽转换转换为基础字段的类型,则该方法将抛出illegalargumentexception。
这三件事中的一件正在发生。不可能说出哪一个。。。除非你提供一个完整的mcve(有人可以在android仿真器上运行!)。。。但这些迹象表明,您(不知何故)违反了序列化兼容性规则。
注意,由于行号不匹配,我不能确定您使用的android是否与下面的匹配。如果您想确定,您需要在git repo中搜索历史以找到匹配的版本。。。。或者查看设备的特定于供应商的源代码包/repo。

  1. /**
  2. * Reads a collection of field values for the class descriptor
  3. * {@code classDesc} (an {@code ObjectStreamClass}). The
  4. * values will be used to set instance fields in object {@code obj}.
  5. * This is the default mechanism, when emulated fields (an
  6. * {@code GetField}) are not used. Actual values to load are stored
  7. * directly into the object {@code obj}.
  8. *
  9. * @param obj
  10. * Instance in which the fields will be set.
  11. * @param classDesc
  12. * A class descriptor (an {@code ObjectStreamClass})
  13. * defining which fields should be loaded.
  14. *
  15. * @throws IOException
  16. * If an IO exception happened when reading the field values.
  17. * @throws InvalidClassException
  18. * If an incompatible type is being assigned to an emulated
  19. * field.
  20. * @throws OptionalDataException
  21. * If optional data could not be found when reading the
  22. * exception graph
  23. * @throws ClassNotFoundException
  24. * If a class of an object being de-serialized can not be found
  25. *
  26. * @see #readFields
  27. * @see #readObject()
  28. */
  29. private void readFieldValues(Object obj, ObjectStreamClass classDesc) throws OptionalDataException, ClassNotFoundException, IOException {
  30. // Now we must read all fields and assign them to the receiver
  31. ObjectStreamField[] fields = classDesc.getLoadFields();
  32. fields = (fields == null) ? ObjectStreamClass.NO_FIELDS : fields;
  33. Class<?> declaringClass = classDesc.forClass();
  34. if (declaringClass == null && mustResolve) {
  35. throw new ClassNotFoundException(classDesc.getName());
  36. }
  37. for (ObjectStreamField fieldDesc : fields) {
  38. Field field = classDesc.getReflectionField(fieldDesc);
  39. if (field != null && Modifier.isTransient(field.getModifiers())) {
  40. field = null; // No setting transient fields! (http://b/4471249)
  41. }
  42. // We may not have been able to find the field, or it may be transient, but we still
  43. // need to read the value and do the other checking...
  44. try {
  45. Class<?> type = fieldDesc.getTypeInternal();
  46. if (type == byte.class) {
  47. byte b = input.readByte();
  48. if (field != null) {
  49. field.setByte(obj, b);
  50. }
  51. } else if (type == char.class) {
  52. char c = input.readChar();
  53. if (field != null) {
  54. field.setChar(obj, c);
  55. }
  56. } else if (type == double.class) {
  57. double d = input.readDouble();
  58. if (field != null) {
  59. field.setDouble(obj, d);
  60. }
  61. } else if (type == float.class) {
  62. float f = input.readFloat();
  63. if (field != null) {
  64. field.setFloat(obj, f);
  65. }
  66. } else if (type == int.class) {
  67. int i = input.readInt();
  68. if (field != null) {
  69. field.setInt(obj, i);
  70. }
  71. } else if (type == long.class) {
  72. long j = input.readLong();
  73. if (field != null) {
  74. field.setLong(obj, j);
  75. }
  76. } else if (type == short.class) {
  77. short s = input.readShort();
  78. if (field != null) {
  79. field.setShort(obj, s);
  80. }
  81. } else if (type == boolean.class) {
  82. boolean z = input.readBoolean();
  83. if (field != null) {
  84. field.setBoolean(obj, z);
  85. }
  86. } else {
  87. Object toSet = fieldDesc.isUnshared() ? readUnshared() : readObject();
  88. if (toSet != null) {
  89. // Get the field type from the local field rather than
  90. // from the stream's supplied data. That's the field
  91. // we'll be setting, so that's the one that needs to be
  92. // validated.
  93. String fieldName = fieldDesc.getName();
  94. ObjectStreamField localFieldDesc = classDesc.getField(fieldName);
  95. Class<?> fieldType = localFieldDesc.getTypeInternal();
  96. Class<?> valueType = toSet.getClass();
  97. if (!fieldType.isAssignableFrom(valueType)) {
  98. throw new ClassCastException(classDesc.getName() + "." + fieldName + " - " + fieldType + " not compatible with " + valueType);
  99. }
  100. if (field != null) {
  101. field.set(obj, toSet); // <<< --- HERE
  102. }
  103. }
  104. }
  105. } catch (IllegalAccessException iae) {
  106. // ObjectStreamField should have called setAccessible(true).
  107. throw new AssertionError(iae);
  108. } catch (NoSuchFieldError ignored) {
  109. }
  110. }
  111. }
展开查看全部

相关问题