diff options
author | Denis Anisimov <denis@vaadin.com> | 2014-04-06 13:51:25 +0300 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2014-04-10 10:11:03 +0000 |
commit | 2067d4e01045fa4ca1d512322d6442499d6aded0 (patch) | |
tree | e216331effe7ff1893039c148a009e3d7274fa9a /server | |
parent | 00a9af50f3a56a0d1e51113d1ae9690ba37f5052 (diff) | |
download | vaadin-framework-2067d4e01045fa4ca1d512322d6442499d6aded0.tar.gz vaadin-framework-2067d4e01045fa4ca1d512322d6442499d6aded0.zip |
Don't allocate unnecessary memory for empty array of Objects in
MethodProperty (#10446).
Change-Id: Ib8e2cfb42494a9dd3efb5ca62ddea9675a1dab1e
Diffstat (limited to 'server')
-rw-r--r-- | server/src/com/vaadin/data/util/MethodProperty.java | 26 | ||||
-rw-r--r-- | server/tests/src/com/vaadin/data/util/MethodPropertyMemoryConsumption.java | 145 |
2 files changed, 162 insertions, 9 deletions
diff --git a/server/src/com/vaadin/data/util/MethodProperty.java b/server/src/com/vaadin/data/util/MethodProperty.java index 0464d50b62..d7323d872f 100644 --- a/server/src/com/vaadin/data/util/MethodProperty.java +++ b/server/src/com/vaadin/data/util/MethodProperty.java @@ -19,6 +19,7 @@ package com.vaadin.data.util; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; @@ -85,6 +86,10 @@ public class MethodProperty<T> extends AbstractProperty<T> { */ private transient Class<? extends T> type; + private static final Object[] DEFAULT_GET_ARGS = new Object[0]; + + private static final Object[] DEFAULT_SET_ARGS = new Object[1]; + /* Special serialization to handle method references */ private void writeObject(java.io.ObjectOutputStream out) throws IOException { out.defaultWriteObject(); @@ -120,8 +125,9 @@ public class MethodProperty<T> extends AbstractProperty<T> { Class<T> class1 = (Class<T>) SerializerHelper.readClass(in); type = class1; instance = in.readObject(); - setArgs = (Object[]) in.readObject(); - getArgs = (Object[]) in.readObject(); + Object[] setArgs = (Object[]) in.readObject(); + Object[] getArgs = (Object[]) in.readObject(); + setArguments(getArgs, setArgs, setArgumentIndex); String name = (String) in.readObject(); Class<?>[] paramTypes = SerializerHelper.readClassArray(in); if (name != null) { @@ -219,7 +225,7 @@ public class MethodProperty<T> extends AbstractProperty<T> { type = (Class<T>) returnType; } - setArguments(new Object[] {}, new Object[] { null }, 0); + setArguments(DEFAULT_GET_ARGS, DEFAULT_SET_ARGS, 0); this.instance = instance; } @@ -627,13 +633,15 @@ public class MethodProperty<T> extends AbstractProperty<T> { */ public void setArguments(Object[] getArgs, Object[] setArgs, int setArgumentIndex) { - this.getArgs = new Object[getArgs.length]; - for (int i = 0; i < getArgs.length; i++) { - this.getArgs[i] = getArgs[i]; + if (getArgs.length == 0) { + this.getArgs = DEFAULT_GET_ARGS; + } else { + this.getArgs = Arrays.copyOf(getArgs, getArgs.length); } - this.setArgs = new Object[setArgs.length]; - for (int i = 0; i < setArgs.length; i++) { - this.setArgs[i] = setArgs[i]; + if (Arrays.equals(setArgs, DEFAULT_SET_ARGS)) { + this.setArgs = DEFAULT_SET_ARGS; + } else { + this.setArgs = Arrays.copyOf(setArgs, setArgs.length); } this.setArgumentIndex = setArgumentIndex; } diff --git a/server/tests/src/com/vaadin/data/util/MethodPropertyMemoryConsumption.java b/server/tests/src/com/vaadin/data/util/MethodPropertyMemoryConsumption.java new file mode 100644 index 0000000000..caff33cf50 --- /dev/null +++ b/server/tests/src/com/vaadin/data/util/MethodPropertyMemoryConsumption.java @@ -0,0 +1,145 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.data.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Field; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Test for MethodProperty: don't allocate unnecessary Object arrays. + * + * @since 7.2 + * @author Vaadin Ltd + */ +public class MethodPropertyMemoryConsumption { + + @Test + public void testSetArguments() throws NoSuchFieldException, + SecurityException, IllegalArgumentException, IllegalAccessException { + TestBean bean = new TestBean(); + TestMethodProperty<String> property = new TestMethodProperty<String>( + bean, "name"); + Object[] getArgs = property.getGetArgs(); + Object[] setArgs = property.getSetArgs(); + + Field getArgsField = TestMethodProperty.class + .getDeclaredField("getArgs"); + getArgsField.setAccessible(true); + + Field setArgsField = TestMethodProperty.class + .getDeclaredField("setArgs"); + setArgsField.setAccessible(true); + + Assert.assertSame("setArguments method sets non-default instance" + + " of empty Object array for getArgs", + getArgsField.get(property), getArgs); + + Assert.assertSame("setArguments method sets non-default instance" + + " of empty Object array for setArgs", + setArgsField.get(property), setArgs); + } + + @Test + public void testDefaultCtor() { + TestBean bean = new TestBean(); + TestMethodProperty<String> property = new TestMethodProperty<String>( + bean, "name"); + + Object[] getArgs = property.getGetArgs(); + Object[] setArgs = property.getSetArgs(); + + TestBean otherBean = new TestBean(); + TestMethodProperty<String> otherProperty = new TestMethodProperty<String>( + otherBean, "name"); + Assert.assertSame("setArguments method uses different instance" + + " of empty Object array for getArgs", getArgs, + otherProperty.getGetArgs()); + Assert.assertSame("setArguments method uses different instance" + + " of empty Object array for setArgs", setArgs, + otherProperty.getSetArgs()); + } + + @Test + public void testDefaultArgsSerialization() throws IOException, + ClassNotFoundException { + TestBean bean = new TestBean(); + TestMethodProperty<String> property = new TestMethodProperty<String>( + bean, "name"); + + ByteArrayOutputStream sourceOutStream = new ByteArrayOutputStream(); + ObjectOutputStream outStream = new ObjectOutputStream(sourceOutStream); + outStream.writeObject(property); + + ObjectInputStream inputStream = new ObjectInputStream( + new ByteArrayInputStream(sourceOutStream.toByteArray())); + Object red = inputStream.readObject(); + TestMethodProperty<?> deserialized = (TestMethodProperty<?>) red; + + Assert.assertNotNull("Deseriliation doesn't call setArguments method", + deserialized.getGetArgs()); + Assert.assertNotNull("Deseriliation doesn't call setArguments method", + deserialized.getSetArgs()); + + } + + public static class TestMethodProperty<T> extends MethodProperty<T> { + + public TestMethodProperty(Object instance, String beanPropertyName) { + super(instance, beanPropertyName); + } + + @Override + public void setArguments(Object[] getArgs, Object[] setArgs, + int setArgumentIndex) { + super.setArguments(getArgs, setArgs, setArgumentIndex); + this.getArgs = getArgs; + this.setArgs = setArgs; + } + + Object[] getGetArgs() { + return getArgs; + } + + Object[] getSetArgs() { + return setArgs; + } + + private transient Object[] getArgs; + private transient Object[] setArgs; + } + + public static class TestBean implements Serializable { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + } +} |