diff --git a/geode-core/src/main/java/org/apache/geode/pdx/internal/PdxInstanceImpl.java b/geode-core/src/main/java/org/apache/geode/pdx/internal/PdxInstanceImpl.java index 0c19a7909474..d7840231089d 100644 --- a/geode-core/src/main/java/org/apache/geode/pdx/internal/PdxInstanceImpl.java +++ b/geode-core/src/main/java/org/apache/geode/pdx/internal/PdxInstanceImpl.java @@ -41,6 +41,7 @@ import org.apache.geode.internal.tcp.ByteBufferInputStream; import org.apache.geode.internal.tcp.ByteBufferInputStream.ByteSource; import org.apache.geode.internal.tcp.ByteBufferInputStream.ByteSourceFactory; +import org.apache.geode.internal.util.Hex; import org.apache.geode.pdx.JSONFormatter; import org.apache.geode.pdx.PdxSerializationException; import org.apache.geode.pdx.WritablePdxInstance; @@ -464,8 +465,30 @@ public String toString() { result.append(fieldType.getFieldName()); result.append("="); try { - // TODO check to see if getField returned an array and if it did use Arrays.deepToString - result.append(ur.readField(fieldType.getFieldName())); + final Object value = ur.readField(fieldType.getFieldName()); + if (value instanceof byte[]) { + result.append(Hex.toHex((byte[]) value)); + } else if (value.getClass().isArray()) { + if (value instanceof short[]) { + result.append(Arrays.toString((short[]) value)); + } else if (value instanceof int[]) { + result.append(Arrays.toString((int[]) value)); + } else if (value instanceof long[]) { + result.append(Arrays.toString((long[]) value)); + } else if (value instanceof char[]) { + result.append(Arrays.toString((char[]) value)); + } else if (value instanceof float[]) { + result.append(Arrays.toString((float[]) value)); + } else if (value instanceof double[]) { + result.append(Arrays.toString((double[]) value)); + } else if (value instanceof boolean[]) { + result.append(Arrays.toString((boolean[]) value)); + } else { + result.append(Arrays.deepToString((Object[]) value)); + } + } else { + result.append(value); + } } catch (RuntimeException e) { result.append(e); } diff --git a/geode-core/src/main/java/org/apache/geode/pdx/internal/WritablePdxInstanceImpl.java b/geode-core/src/main/java/org/apache/geode/pdx/internal/WritablePdxInstanceImpl.java index 1006d963327e..a76323f97dfc 100644 --- a/geode-core/src/main/java/org/apache/geode/pdx/internal/WritablePdxInstanceImpl.java +++ b/geode-core/src/main/java/org/apache/geode/pdx/internal/WritablePdxInstanceImpl.java @@ -34,13 +34,13 @@ public WritablePdxInstanceImpl(PdxReaderImpl original) { } private synchronized void dirtyField(PdxField f, Object value) { - if (this.dirtyFields == null) { - this.dirtyFields = new Object[getPdxType().getFieldCount()]; + if (dirtyFields == null) { + dirtyFields = new Object[getPdxType().getFieldCount()]; } if (value == null) { value = NULL_TOKEN; } - this.dirtyFields[f.getFieldIndex()] = value; + dirtyFields[f.getFieldIndex()] = value; clearCachedState(); } @@ -49,10 +49,10 @@ private synchronized void dirtyField(PdxField f, Object value) { */ @Override protected synchronized PdxReaderImpl getUnmodifiableReader(String fieldName) { - if (this.dirtyFields != null) { + if (dirtyFields != null) { PdxField f = getPdxType().getPdxField(fieldName); if (f != null) { - if (this.dirtyFields[f.getFieldIndex()] != null) { + if (dirtyFields[f.getFieldIndex()] != null) { return getUnmodifiableReader(); } } @@ -75,7 +75,7 @@ public synchronized int hashCode() { */ @Override protected synchronized PdxReaderImpl getUnmodifiableReader() { - if (this.dirtyFields != null) { + if (dirtyFields != null) { PdxOutputStream os = new PdxOutputStream(basicSize() + PdxWriterImpl.HEADER_SIZE); PdxWriterImpl writer; if (getPdxType().getHasDeletedField()) { @@ -92,7 +92,7 @@ protected synchronized PdxReaderImpl getUnmodifiableReader() { if (f.isDeleted()) { continue; } - Object dv = this.dirtyFields[f.getFieldIndex()]; + Object dv = dirtyFields[f.getFieldIndex()]; if (dv != null) { if (dv == NULL_TOKEN) { dv = null; @@ -106,7 +106,7 @@ protected synchronized PdxReaderImpl getUnmodifiableReader() { ByteBuffer bb = os.toByteBuffer(); bb.position(PdxWriterImpl.HEADER_SIZE); basicSetBuffer(bb.slice()); - this.dirtyFields = null; + dirtyFields = null; } return new PdxReaderImpl(this); } diff --git a/geode-core/src/test/java/org/apache/geode/pdx/internal/PdxInstanceImplTest.java b/geode-core/src/test/java/org/apache/geode/pdx/internal/PdxInstanceImplTest.java new file mode 100644 index 000000000000..15df60e2c520 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/pdx/internal/PdxInstanceImplTest.java @@ -0,0 +1,202 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You 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 org.apache.geode.pdx.internal; + +import static org.apache.commons.lang.StringUtils.substringAfter; +import static org.apache.geode.distributed.ConfigurationProperties.DISTRIBUTED_SYSTEM_ID; +import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; +import static org.junit.Assert.assertEquals; + +import java.io.Serializable; + +import org.apache.commons.lang.StringUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.cache.CacheFactory; +import org.apache.geode.internal.cache.GemFireCacheImpl; +import org.apache.geode.pdx.PdxInstance; +import org.apache.geode.test.junit.categories.IntegrationTest; +import org.apache.geode.test.junit.categories.SerializationTest; + +@Category({IntegrationTest.class, SerializationTest.class}) +public class PdxInstanceImplTest { + private GemFireCacheImpl cache; + + @Before + public void setUp() { + cache = (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0") + .set(DISTRIBUTED_SYSTEM_ID, "255").setPdxReadSerialized(true).create(); + } + + @After + public void tearDown() { + cache.close(); + } + + @Test + public void testToStringForEmpty() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForEmpty", false, cache).create(); + assertEquals("testToStringForEmpty]{}", substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForInteger() { + PdxInstance instance = PdxInstanceFactoryImpl.newCreator("testToStringForInteger", false, cache) + .writeInt("intField", 37).create(); + assertEquals("testToStringForInteger]{intField=37}", substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForString() { + PdxInstance instance = PdxInstanceFactoryImpl.newCreator("testToStringForString", false, cache) + .writeString("stringField", "MOOF!").create(); + assertEquals("testToStringForString]{stringField=MOOF!}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForBooleanLongDoubleAndString() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForBooleanLongDoubleAndString", false, cache) + .writeBoolean("booleanField", Boolean.TRUE).writeLong("longField", 37L) + .writeDouble("doubleField", 3.1415).writeString("stringField", "MOOF!").create(); + assertEquals( + "testToStringForBooleanLongDoubleAndString]{booleanField=true, doubleField=3.1415, longField=37, stringField=MOOF!}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForObject() { + PdxInstance instance = PdxInstanceFactoryImpl.newCreator("testToStringForObject", false, cache) + .writeObject("objectField", new SerializableObject("Dave")).create(); + assertEquals("testToStringForObject]{objectField=Dave}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForByteArray() { + PdxInstance instance = PdxInstanceFactoryImpl + .newCreator("testToStringForByteArray", false, cache).writeByteArray("byteArrayField", + new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF}) + .create(); + assertEquals("testToStringForByteArray]{byteArrayField=DEADBEEF}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForObjectArray() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForObjectArray", false, cache) + .writeObjectArray("objectArrayField", + new Object[] {new SerializableObject("Dave"), new SerializableObject("Stewart")}) + .create(); + assertEquals("testToStringForObjectArray]{objectArrayField=[Dave, Stewart]}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForIntegerArray() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForIntegerArray", false, cache) + .writeObjectArray("integerArrayField", new Integer[] {new Integer(37), new Integer(42)}) + .create(); + assertEquals("testToStringForIntegerArray]{integerArrayField=[37, 42]}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForShortArray() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForShortArray", false, cache) + .writeShortArray("shortArrayField", new short[] {37, 42}).create(); + assertEquals("testToStringForShortArray]{shortArrayField=[37, 42]}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForIntArray() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForIntArray", false, cache) + .writeIntArray("intArrayField", new int[] {37, 42}).create(); + assertEquals("testToStringForIntArray]{intArrayField=[37, 42]}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForLongArray() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForLongArray", false, cache) + .writeLongArray("longArrayField", new long[] {37L, 42L}).create(); + assertEquals("testToStringForLongArray]{longArrayField=[37, 42]}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForCharArray() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForCharArray", false, cache) + .writeCharArray("charArrayField", new char[] {'o', 'k'}).create(); + assertEquals("testToStringForCharArray]{charArrayField=[o, k]}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForFloatArray() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForFloatArray", false, cache) + .writeFloatArray("floatArrayField", new float[] {3.14159F, 2.71828F}).create(); + assertEquals("testToStringForFloatArray]{floatArrayField=[3.14159, 2.71828]}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForDoubleArray() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForDoubleArray", false, cache) + .writeDoubleArray("doubleArrayField", new double[] {3.14159, 2.71828}).create(); + assertEquals("testToStringForDoubleArray]{doubleArrayField=[3.14159, 2.71828]}", + substringAfter(instance.toString(), ",")); + } + + @Test + public void testToStringForBooleanArray() { + PdxInstance instance = + PdxInstanceFactoryImpl.newCreator("testToStringForBooleanArray", false, cache) + .writeBooleanArray("booleanArrayField", new boolean[] {false, true}).create(); + assertEquals("testToStringForBooleanArray]{booleanArrayField=[false, true]}", + substringAfter(instance.toString(), ",")); + } + + static class SerializableObject implements Serializable { + String name; + + public SerializableObject() { + // Do nothing. + } + + public SerializableObject(String name) { + this.name = name; + } + + @Override + public String toString() { + return StringUtils.trimToEmpty(name); + } + } +}