]> source.dussan.org Git - vaadin-framework.git/commitdiff
Unify basic instance creation and related error reporting (#9704)
authorLeif Åstrand <legioth@gmail.com>
Tue, 1 Aug 2017 08:00:21 +0000 (11:00 +0300)
committerHenri Sara <henri.sara@gmail.com>
Tue, 1 Aug 2017 08:00:21 +0000 (11:00 +0300)
12 files changed:
server/src/main/java/com/vaadin/data/Binder.java
server/src/main/java/com/vaadin/navigator/Navigator.java
server/src/main/java/com/vaadin/server/AbstractClientConnector.java
server/src/main/java/com/vaadin/server/BootstrapHandler.java
server/src/main/java/com/vaadin/server/JsonCodec.java
server/src/main/java/com/vaadin/server/LegacyCommunicationManager.java
server/src/main/java/com/vaadin/server/LegacyVaadinPortlet.java
server/src/main/java/com/vaadin/server/LegacyVaadinServlet.java
server/src/main/java/com/vaadin/server/ServletPortletHelper.java
server/src/main/java/com/vaadin/server/UIProvider.java
server/src/main/java/com/vaadin/ui/declarative/Design.java
server/src/main/java/com/vaadin/util/ReflectTools.java

index ae467be123e26f69f75cda359080a1faae43d1c6..43f893e33f1c0bd74eafe7945ea4ff61209256de 100644 (file)
@@ -2261,12 +2261,10 @@ public class Binder<BEAN> implements Serializable {
     private HasValue<?> makeFieldInstance(
             Class<? extends HasValue<?>> fieldClass) {
         try {
-            return fieldClass.newInstance();
-        } catch (InstantiationException | IllegalAccessException e) {
-            throw new IllegalStateException(
-                    String.format("Couldn't create an '%s' type instance",
-                            fieldClass.getName()),
-                    e);
+            return ReflectTools.createInstance(fieldClass);
+        } catch (IllegalArgumentException e) {
+            // Rethrow as the exception type declared for bindInstanceFields
+            throw new IllegalStateException(e);
         }
     }
 
index 23d6cc5f913536b75970e81ecf9bc9f3fe092143..6b18cd4000901d7708e6f1f4b48b427ea55fc908 100644 (file)
@@ -34,6 +34,7 @@ import com.vaadin.ui.ComponentContainer;
 import com.vaadin.ui.CssLayout;
 import com.vaadin.ui.SingleComponentContainer;
 import com.vaadin.ui.UI;
+import com.vaadin.util.ReflectTools;
 
 /**
  * A navigator utility that allows switching of views in a part of an
@@ -315,15 +316,7 @@ public class Navigator implements Serializable {
         @Override
         public View getView(String viewName) {
             if (this.viewName.equals(viewName)) {
-                try {
-                    View view = viewClass.newInstance();
-                    return view;
-                } catch (InstantiationException | IllegalAccessException e) {
-                    // TODO error handling
-                    throw new RuntimeException(e);
-                }
-                // TODO error handling
-
+                return ReflectTools.createInstance(viewClass);
             }
             return null;
         }
@@ -1061,11 +1054,7 @@ public class Navigator implements Serializable {
         setErrorProvider(new ViewProvider() {
             @Override
             public View getView(String viewName) {
-                try {
-                    return viewClass.newInstance();
-                } catch (Exception e) {
-                    throw new RuntimeException(e);
-                }
+                return ReflectTools.createInstance(viewClass);
             }
 
             @Override
index 3bce462522fe768cd68b7f60f1ac546cdd7891c5..fc05f678600747657dc6d7022a60dc3ff8cf8e2f 100644 (file)
@@ -45,6 +45,7 @@ import com.vaadin.ui.Component.Event;
 import com.vaadin.ui.HasComponents;
 import com.vaadin.ui.LegacyComponent;
 import com.vaadin.ui.UI;
+import com.vaadin.util.ReflectTools;
 
 import elemental.json.JsonObject;
 import elemental.json.JsonValue;
@@ -295,7 +296,7 @@ public abstract class AbstractClientConnector
      */
     protected SharedState createState() {
         try {
-            return getStateType().newInstance();
+            return ReflectTools.createInstance(getStateType());
         } catch (Exception e) {
             throw new RuntimeException("Error creating state of type "
                     + getStateType().getName() + " for " + getClass().getName(),
index 01fd2bf880fe26080b1bb352be1cb36b1d2dbc90..13a485216468cfc5803dab481afd7fd2e07522f5 100644 (file)
@@ -53,6 +53,7 @@ import com.vaadin.shared.communication.PushMode;
 import com.vaadin.ui.Dependency;
 import com.vaadin.ui.Dependency.Type;
 import com.vaadin.ui.UI;
+import com.vaadin.util.ReflectTools;
 
 import elemental.json.Json;
 import elemental.json.JsonException;
@@ -262,7 +263,7 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
 
     /**
      * The URI resolver used in the bootstrap process.
-     * 
+     *
      * @since 8.1
      */
     protected static class BootstrapUriResolver extends VaadinUriResolver {
@@ -541,7 +542,8 @@ public abstract class BootstrapHandler extends SynchronizedRequestHandler {
             Class<? extends ViewportGenerator> viewportGeneratorClass = viewportGeneratorClassAnnotation
                     .value();
             try {
-                viewportContent = viewportGeneratorClass.newInstance()
+                viewportContent = ReflectTools
+                        .createInstance(viewportGeneratorClass)
                         .getViewport(context.getRequest());
             } catch (Exception e) {
                 throw new RuntimeException(
index 9c105d505e929e49e1fb150a0810147f2cac1bfe..a7f94de4685a72094f166f1c3a0a6c153f6c6605 100644 (file)
@@ -46,6 +46,7 @@ import com.vaadin.shared.JsonConstants;
 import com.vaadin.shared.communication.UidlValue;
 import com.vaadin.ui.Component;
 import com.vaadin.ui.ConnectorTracker;
+import com.vaadin.util.ReflectTools;
 
 import elemental.json.Json;
 import elemental.json.JsonArray;
@@ -611,7 +612,7 @@ public class JsonCodec implements Serializable {
         Class<?> targetClass = getClassForType(targetType);
 
         try {
-            Object decodedObject = targetClass.newInstance();
+            Object decodedObject = ReflectTools.createInstance(targetClass);
             for (BeanProperty property : getProperties(targetClass)) {
 
                 String fieldName = property.getName();
index f3a56a2c53f8ff63296f410bce2d4842a48e72ad..45244425319d7a210e87e298f9a9e1a20d11994a 100644 (file)
@@ -39,6 +39,7 @@ import com.vaadin.ui.ConnectorTracker;
 import com.vaadin.ui.HasComponents;
 import com.vaadin.ui.SelectiveRenderer;
 import com.vaadin.ui.UI;
+import com.vaadin.util.ReflectTools;
 
 import elemental.json.JsonObject;
 import elemental.json.JsonValue;
@@ -124,7 +125,7 @@ public class LegacyCommunicationManager implements Serializable {
         }
 
         try {
-            SharedState referenceState = stateType.newInstance();
+            SharedState referenceState = ReflectTools.createInstance(stateType);
             EncodeResult encodeResult = JsonCodec.encode(referenceState, null,
                     stateType, null);
             return encodeResult.getEncodedValue();
index 9f229056646b06c1b12a5d5d77c6b502ea997185..831239096a997615d37fde36c875f9205329a576 100644 (file)
@@ -20,6 +20,8 @@ import javax.portlet.PortletConfig;
 import javax.portlet.PortletException;
 import javax.portlet.PortletRequest;
 
+import com.vaadin.util.ReflectTools;
+
 public class LegacyVaadinPortlet extends VaadinPortlet {
 
     private static final LegacyApplicationUIProvider provider = new LegacyApplicationUIProvider() {
@@ -70,7 +72,7 @@ public class LegacyVaadinPortlet extends VaadinPortlet {
             throws PortletException {
         try {
             Class<? extends LegacyApplication> applicationClass = getApplicationClass();
-            return applicationClass.newInstance();
+            return ReflectTools.createInstance(applicationClass);
         } catch (Exception e) {
             throw new PortletException(e);
         }
index 40f76ebd1a8ffb69618acaae8a44f3ddd158cb31..70174fdc32c1492d14e9db38df3016196136b731 100644 (file)
@@ -20,6 +20,8 @@ import javax.servlet.ServletConfig;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 
+import com.vaadin.util.ReflectTools;
+
 public class LegacyVaadinServlet extends VaadinServlet {
 
     private static final UIProvider provider = new LegacyApplicationUIProvider() {
@@ -69,7 +71,7 @@ public class LegacyVaadinServlet extends VaadinServlet {
             throws ServletException {
         try {
             Class<? extends LegacyApplication> applicationClass = getApplicationClass();
-            return applicationClass.newInstance();
+            return ReflectTools.createInstance(applicationClass);
         } catch (Exception e) {
             throw new ServletException(e);
         }
index bf7b1c8452a5307bc4b553a724b8e9474b488c30..a679e97d2e43c1e3fe5d907b0519ca59e553bff9 100644 (file)
@@ -22,6 +22,7 @@ import java.util.Properties;
 import com.vaadin.shared.ApplicationConstants;
 import com.vaadin.ui.Component;
 import com.vaadin.ui.UI;
+import com.vaadin.util.ReflectTools;
 
 /**
  * Contains helper methods shared by {@link VaadinServlet} and
@@ -176,17 +177,13 @@ public class ServletPortletHelper implements Serializable {
             Class<?> providerClass = classLoader.loadClass(uiProviderProperty);
             Class<? extends UIProvider> subclass = providerClass
                     .asSubclass(UIProvider.class);
-            return subclass.newInstance();
+            return ReflectTools.createInstance(subclass);
         } catch (ClassNotFoundException e) {
             throw new ServiceException(
                     "Could not load UIProvider class " + uiProviderProperty, e);
         } catch (ClassCastException e) {
             throw new ServiceException("UIProvider class " + uiProviderProperty
                     + " does not extend UIProvider", e);
-        } catch (InstantiationException | IllegalAccessException e) {
-            throw new ServiceException(
-                    "Could not instantiate UIProvider " + uiProviderProperty,
-                    e);
         }
     }
 
index a652b423ff28bbb5e85f46b4b354f2d903a17ca5..11d5d43109b670b155a575c71a46585caa373de4 100644 (file)
@@ -31,6 +31,7 @@ import com.vaadin.annotations.Widgetset;
 import com.vaadin.shared.communication.PushMode;
 import com.vaadin.shared.ui.ui.Transport;
 import com.vaadin.ui.UI;
+import com.vaadin.util.ReflectTools;
 
 public abstract class UIProvider implements Serializable {
 
@@ -40,13 +41,7 @@ public abstract class UIProvider implements Serializable {
     public abstract Class<? extends UI> getUIClass(UIClassSelectionEvent event);
 
     public UI createInstance(UICreateEvent event) {
-        try {
-            return event.getUIClass().newInstance();
-        } catch (InstantiationException e) {
-            throw new RuntimeException("Could not instantiate UI class", e);
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException("Could not access UI class", e);
-        }
+        return ReflectTools.createInstance(event.getUIClass());
     }
 
     /**
index b051c68a9069c597e26bebbe925e092992f6d29e..78288737a0901c51650c055a4fc5a388cceb50a6 100644 (file)
@@ -44,6 +44,7 @@ import com.vaadin.ui.Composite;
 import com.vaadin.ui.CustomComponent;
 import com.vaadin.ui.declarative.DesignContext.ComponentCreatedEvent;
 import com.vaadin.ui.declarative.DesignContext.ComponentCreationListener;
+import com.vaadin.util.ReflectTools;
 
 /**
  * Design is used for reading a component hierarchy from an html string or input
@@ -175,7 +176,7 @@ public class Design implements Serializable {
                             + " which is not a Vaadin Component class";
 
             try {
-                return componentClass.newInstance();
+                return ReflectTools.createInstance(componentClass);
             } catch (Exception e) {
                 throw new DesignException(
                         "Could not create component " + fullyQualifiedClassName,
index 8ff8ddcbb0f4fa9559e1e27b9ce68118f932a3a6..4728c76c47927217e7c33af4443aab0dca216134 100644 (file)
@@ -20,6 +20,7 @@ import java.beans.PropertyDescriptor;
 import java.io.Serializable;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 
 /**
  * An util class with helpers for reflection operations. Used internally by
@@ -29,6 +30,14 @@ import java.lang.reflect.Method;
  * @since 6.2
  */
 public class ReflectTools implements Serializable {
+
+    static final String CREATE_INSTANCE_FAILED = "Unable to create an instance of {0}. Make sure it has a no-arg constructor";
+    static final String CREATE_INSTANCE_FAILED_FOR_NON_STATIC_MEMBER_CLASS = "Unable to create an instance of {0}. Make sure the class is static if it is a nested class.";
+    static final String CREATE_INSTANCE_FAILED_ACCESS_EXCEPTION = "Unable to create an instance of {0}. Make sure the class is public and that is has a public no-arg constructor.";
+    static final String CREATE_INSTANCE_FAILED_NO_PUBLIC_NOARG_CONSTRUCTOR = "Unable to create an instance of {0}. Make sure the class has a public no-arg constructor.";
+    static final String CREATE_INSTANCE_FAILED_LOCAL_CLASS = "Cannot instantiate local class '%s'. Move class declaration outside the method.";
+    static final String CREATE_INSTANCE_FAILED_CONSTRUCTOR_THREW_EXCEPTION = "Unable to create an instance of {0}. The constructor threw an exception.";
+
     /**
      * Locates the method in the given class. Returns null if the method is not
      * found. Throws an ExceptionInInitializerError if there is a problem
@@ -249,4 +258,67 @@ public class ReflectTools implements Serializable {
 
         return currentClass;
     }
+
+    /**
+     * Creates a instance of the given class with a no-arg constructor.
+     * <p>
+     * Catches all exceptions which might occur and wraps them in a
+     * {@link IllegalArgumentException} with a descriptive error message hinting
+     * of what might be wrong with the class that could not be instantiated.
+     *
+     * @param cls
+     *            the class to instantiate
+     * @return an instance of the class
+     * @since 8.1.1
+     */
+    public static <T> T createInstance(Class<T> cls) {
+        checkClassAccessibility(cls);
+        try {
+            return cls.getConstructor().newInstance();
+        } catch (NoSuchMethodException e) {
+            throw new IllegalArgumentException(String.format(
+                    CREATE_INSTANCE_FAILED_NO_PUBLIC_NOARG_CONSTRUCTOR,
+                    cls.getName()), e);
+        } catch (InstantiationException e) {
+            if (cls.isMemberClass() && !Modifier.isStatic(cls.getModifiers())) {
+                throw new IllegalArgumentException(String.format(
+                        CREATE_INSTANCE_FAILED_FOR_NON_STATIC_MEMBER_CLASS,
+                        cls.getName()), e);
+            } else {
+                throw new IllegalArgumentException(
+                        String.format(CREATE_INSTANCE_FAILED, cls.getName()),
+                        e);
+            }
+        } catch (IllegalAccessException e) {
+            throw new IllegalArgumentException(String.format(
+                    CREATE_INSTANCE_FAILED_ACCESS_EXCEPTION, cls.getName()), e);
+        } catch (IllegalArgumentException e) {
+            throw new IllegalArgumentException(
+                    String.format(CREATE_INSTANCE_FAILED, cls.getName()), e);
+        } catch (InvocationTargetException e) {
+            throw new IllegalArgumentException(String.format(
+                    CREATE_INSTANCE_FAILED_CONSTRUCTOR_THREW_EXCEPTION,
+                    cls.getName()), e);
+        }
+    }
+
+    /**
+     * Makes a check whether the provided class is externally accessible for
+     * instantiation (e.g. it's not inner class (nested and not static) and is
+     * not a local class).
+     *
+     * @param cls
+     *            type to check
+     */
+    private static void checkClassAccessibility(Class<?> cls) {
+        if (cls.isMemberClass() && !Modifier.isStatic(cls.getModifiers())) {
+            throw new IllegalArgumentException(String.format(
+                    CREATE_INSTANCE_FAILED_FOR_NON_STATIC_MEMBER_CLASS,
+                    cls.getName()));
+        } else if (cls.isLocalClass()) {
+            throw new IllegalArgumentException(String
+                    .format(CREATE_INSTANCE_FAILED_LOCAL_CLASS, cls.getName()));
+        }
+    }
+
 }