From 5eaf653de91210adf6263ebf99a92b09bd1cf28e Mon Sep 17 00:00:00 2001 From: Stephen Gold Date: Tue, 17 Sep 2019 17:58:44 -0700 Subject: [PATCH] address issue #1119 (serialization with protected/private constructor) (#1181) * address issue #1119 (serialization with protected/private constructor) * remove an unnecessary step in findNoArgConstructor() * use getDeclaredConstructor() in place of the for-loop * simplify by throwing the exception in findNoArgContructor() --- .../com/jme3/export/SavableClassUtil.java | 41 +++++++++++++++---- .../jme3/export/binary/BinaryImporter.java | 11 +---- .../com/jme3/export/xml/DOMInputCapsule.java | 4 +- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java b/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java index d41e6bb92..2e206a416 100644 --- a/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java +++ b/jme3-core/src/main/java/com/jme3/export/SavableClassUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 jMonkeyEngine + * Copyright (c) 2009-2019 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,7 +36,9 @@ import com.jme3.effect.shapes.*; import com.jme3.material.MatParamTexture; import java.io.IOException; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -161,16 +163,19 @@ public class SavableClassUtil { * @return the Savable instance of the class. * @throws InstantiationException thrown if the class does not have an empty constructor. * @throws IllegalAccessException thrown if the class is not accessable. + * @throws java.lang.reflect.InvocationTargetException * @throws ClassNotFoundException thrown if the class name is not in the classpath. - * @throws IOException when loading ctor parameters fails */ - public static Savable fromName(String className) throws InstantiationException, - IllegalAccessException, ClassNotFoundException, IOException { - + public static Savable fromName(String className) + throws ClassNotFoundException, IllegalAccessException, + InstantiationException, InvocationTargetException { className = remapClass(className); + + Constructor noArgConstructor = findNoArgConstructor(className); + noArgConstructor.setAccessible(true); try { - return (Savable) Class.forName(className).newInstance(); - } catch (InstantiationException e) { + return (Savable) noArgConstructor.newInstance(); + } catch (InvocationTargetException | InstantiationException e) { Logger.getLogger(SavableClassUtil.class.getName()).log( Level.SEVERE, "Could not access constructor of class ''{0}" + "''! \n" + "Some types need to have the BinaryImporter set up in a special way. Please doublecheck the setup.", className); @@ -184,6 +189,7 @@ public class SavableClassUtil { } public static Savable fromName(String className, List loaders) throws InstantiationException, + InvocationTargetException, NoSuchMethodException, IllegalAccessException, ClassNotFoundException, IOException { if (loaders == null) { return fromName(className); @@ -208,4 +214,25 @@ public class SavableClassUtil { return fromName(className); } + + /** + * Use reflection to gain access to the no-arg constructor of the named + * class. + * + * @return the pre-existing constructor (not null) + */ + private static Constructor findNoArgConstructor(String className) + throws ClassNotFoundException, InstantiationException { + Class clazz = Class.forName(className); + Constructor result; + try { + result = clazz.getDeclaredConstructor(); + } catch (NoSuchMethodException e) { + throw new InstantiationException( + "Loading requires a no-arg constructor, but class " + + className + " lacks one."); + } + + return result; + } } diff --git a/jme3-core/src/plugins/java/com/jme3/export/binary/BinaryImporter.java b/jme3-core/src/plugins/java/com/jme3/export/binary/BinaryImporter.java index d4c24054d..93f082337 100644 --- a/jme3-core/src/plugins/java/com/jme3/export/binary/BinaryImporter.java +++ b/jme3-core/src/plugins/java/com/jme3/export/binary/BinaryImporter.java @@ -345,16 +345,7 @@ public final class BinaryImporter implements JmeImporter { return out; - } catch (IOException e) { - logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int id)", "Exception", e); - return null; - } catch (ClassNotFoundException e) { - logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int id)", "Exception", e); - return null; - } catch (InstantiationException e) { - logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int id)", "Exception", e); - return null; - } catch (IllegalAccessException e) { + } catch (Exception e) { logger.logp(Level.SEVERE, this.getClass().toString(), "readObject(int id)", "Exception", e); return null; } diff --git a/jme3-plugins/src/xml/java/com/jme3/export/xml/DOMInputCapsule.java b/jme3-plugins/src/xml/java/com/jme3/export/xml/DOMInputCapsule.java index 6b0eb39b7..22779cf25 100644 --- a/jme3-plugins/src/xml/java/com/jme3/export/xml/DOMInputCapsule.java +++ b/jme3-plugins/src/xml/java/com/jme3/export/xml/DOMInputCapsule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2012 jMonkeyEngine + * Copyright (c) 2009-2019 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,6 +38,7 @@ import com.jme3.export.SavableClassUtil; import com.jme3.util.BufferUtils; import com.jme3.util.IntMap; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.nio.ByteBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; @@ -962,6 +963,7 @@ public class DOMInputCapsule implements InputCapsule { private Savable readSavableFromCurrentElem(Savable defVal) throws InstantiationException, ClassNotFoundException, + NoSuchMethodException, InvocationTargetException, IOException, IllegalAccessException { Savable ret = defVal; Savable tmp = null;