Skip to content
This repository
Browse code

Fixes #88 - broken serialization of subclasses of core JDOM classes (…

…like custom subclasses of Element).

Upgrade the serialiazion test-code to report exceptions better.
Add a test-case that checks that all subclasses are serializable.
  • Loading branch information...
commit 17e18fe177d8661cae4d9e08c5a9ef3610000217 1 parent 003f12c
Rolf rolfl authored
16 core/src/java/org/jdom2/CloneBase.java
@@ -61,6 +61,22 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
61 61 * @author Rolf Lear
62 62 */
63 63 class CloneBase implements Cloneable {
  64 +
  65 + /**
  66 + * Change the permission of the no-arg constructor from public to protcted.
  67 + * <p>
  68 + * Otherwise package-private class's constructor is not really public. Changing this to
  69 + * 'protected' makes this constructor available to all subclasses regardless of the
  70 + * subclass's package. This in turn makes it possible to make all th subclasses of this
  71 + * CloneBase class serializable.
  72 + *
  73 + */
  74 + protected CloneBase() {
  75 + // This constructor is needed to solve issue #88
  76 + // There needs to be a no-arg constructor accessible by all
  77 + // potential subclasses of CloneBase, and 'protected' is actually more
  78 + // accessible than 'public' since this is a package-private class.
  79 + }
64 80
65 81 /**
66 82 * Return a deep clone of this instance. Even if this instance has a parent,
10 test/src/java/org/jdom2/test/cases/serialize/SAttribute.java
... ... @@ -0,0 +1,10 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import org.jdom2.Attribute;
  4 +
  5 +@SuppressWarnings("javadoc")
  6 +public class SAttribute extends Attribute {
  7 +
  8 + private static final long serialVersionUID = 1L;
  9 +
  10 +}
10 test/src/java/org/jdom2/test/cases/serialize/SCDATA.java
... ... @@ -0,0 +1,10 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import org.jdom2.CDATA;
  4 +
  5 +@SuppressWarnings("javadoc")
  6 +public class SCDATA extends CDATA {
  7 +
  8 + private static final long serialVersionUID = 1L;
  9 +
  10 +}
10 test/src/java/org/jdom2/test/cases/serialize/SComment.java
... ... @@ -0,0 +1,10 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import org.jdom2.Comment;
  4 +
  5 +@SuppressWarnings("javadoc")
  6 +public class SComment extends Comment {
  7 +
  8 + private static final long serialVersionUID = 1L;
  9 +
  10 +}
10 test/src/java/org/jdom2/test/cases/serialize/SDocType.java
... ... @@ -0,0 +1,10 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import org.jdom2.DocType;
  4 +
  5 +@SuppressWarnings("javadoc")
  6 +public class SDocType extends DocType {
  7 +
  8 + private static final long serialVersionUID = 1L;
  9 +
  10 +}
10 test/src/java/org/jdom2/test/cases/serialize/SElement.java
... ... @@ -0,0 +1,10 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import org.jdom2.Element;
  4 +
  5 +@SuppressWarnings("javadoc")
  6 +public class SElement extends Element {
  7 +
  8 + private static final long serialVersionUID = 1L;
  9 +
  10 +}
10 test/src/java/org/jdom2/test/cases/serialize/SEntityRef.java
... ... @@ -0,0 +1,10 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import org.jdom2.EntityRef;
  4 +
  5 +@SuppressWarnings("javadoc")
  6 +public class SEntityRef extends EntityRef {
  7 +
  8 + private static final long serialVersionUID = 1L;
  9 +
  10 +}
18 test/src/java/org/jdom2/test/cases/serialize/SFilter.java
... ... @@ -0,0 +1,18 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import org.jdom2.filter.AbstractFilter;
  4 +
  5 +@SuppressWarnings("javadoc")
  6 +public class SFilter extends AbstractFilter<Integer> {
  7 +
  8 + private static final long serialVersionUID = 1L;
  9 +
  10 + @Override
  11 + public Integer filter(Object content) {
  12 + if (content instanceof Integer) {
  13 + return (Integer)content;
  14 + }
  15 + return null;
  16 + }
  17 +
  18 +}
10 test/src/java/org/jdom2/test/cases/serialize/SProcessingInstruction.java
... ... @@ -0,0 +1,10 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import org.jdom2.ProcessingInstruction;
  4 +
  5 +@SuppressWarnings("javadoc")
  6 +public class SProcessingInstruction extends ProcessingInstruction {
  7 +
  8 + private static final long serialVersionUID = 1L;
  9 +
  10 +}
10 test/src/java/org/jdom2/test/cases/serialize/SText.java
... ... @@ -0,0 +1,10 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import org.jdom2.Text;
  4 +
  5 +@SuppressWarnings("javadoc")
  6 +public class SText extends Text {
  7 +
  8 + private static final long serialVersionUID = 1L;
  9 +
  10 +}
55 test/src/java/org/jdom2/test/cases/serialize/TestSubclassSerializables.java
... ... @@ -0,0 +1,55 @@
  1 +package org.jdom2.test.cases.serialize;
  2 +
  3 +import static org.jdom2.test.util.UnitTestUtil.deSerialize;
  4 +
  5 +import org.junit.Test;
  6 +
  7 +@SuppressWarnings("javadoc")
  8 +public class TestSubclassSerializables {
  9 +
  10 + @Test
  11 + public void testFilter() {
  12 + deSerialize(new SFilter());
  13 + }
  14 +
  15 + @Test
  16 + public void testAttribute() {
  17 + deSerialize(new SAttribute());
  18 + }
  19 +
  20 + @Test
  21 + public void testCDATA() {
  22 + deSerialize(new SComment());
  23 + }
  24 +
  25 + @Test
  26 + public void testComment() {
  27 + deSerialize(new SComment());
  28 + }
  29 +
  30 + @Test
  31 + public void testDocType() {
  32 + deSerialize(new SDocType());
  33 + }
  34 +
  35 + @Test
  36 + public void testElement() {
  37 + deSerialize(new SElement());
  38 + }
  39 +
  40 + @Test
  41 + public void testEntityRef() {
  42 + deSerialize(new SEntityRef());
  43 + }
  44 +
  45 + @Test
  46 + public void testProcessingInstruction() {
  47 + deSerialize(new SProcessingInstruction());
  48 + }
  49 +
  50 + @Test
  51 + public void testText() {
  52 + deSerialize(new SText());
  53 + }
  54 +
  55 +}
28 test/src/java/org/jdom2/test/util/UnitTestUtil.java
@@ -118,11 +118,11 @@ public static final void testNamespaceScope(NamespaceAware content, Namespace...
118 118 * @param input
119 119 * @return
120 120 */
121   - public static final <T extends Serializable> T deSerialize(T input) {
  121 + public static final <T extends Serializable> T deSerialize(final T input) {
122 122 if (input == null) {
123 123 return null;
124 124 }
125   - Class<?> tclass = input.getClass();
  125 + final Class<?> tclass = input.getClass();
126 126 final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
127 127 try {
128 128 final ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
@@ -130,26 +130,26 @@ public static final void testNamespaceScope(NamespaceAware content, Namespace...
130 130 objectOutputStream.writeObject(input);
131 131 }
132 132 catch(final IOException ioException) {
133   - failException("Unable to serialize object" + ioException, ioException);
  133 + failException("Unable to serialize object.", ioException);
134 134 }
135 135 finally {
136 136 try {
137 137 objectOutputStream.close();
138 138 }
139 139 catch(final IOException ioException) {
140   - fail("failed to close object stream while serializing object" + ioException);
  140 + failException("failed to close object stream while serializing object", ioException);
141 141 }
142 142 }
143 143 }
144 144 catch(final IOException ioException) {
145   - fail("unable to serialize object" + ioException);
  145 + failException("unable to serialize object", ioException);
146 146 }
147 147 finally {
148 148 try {
149 149 outputStream.close();
150 150 }
151 151 catch(final IOException ioException) {
152   - fail("failed to close output stream while serializing object" + ioException);
  152 + failException("failed to close output stream while serializing object", ioException);
153 153 }
154 154 }
155 155
@@ -168,27 +168,33 @@ public static final void testNamespaceScope(NamespaceAware content, Namespace...
168 168 objectInputStream.close();
169 169 }
170 170 catch(final IOException ioException) {
171   - fail("failed to close object stream while deserializing object" + ioException);
  171 + failException("failed to close object stream while deserializing object", ioException);
172 172 }
173 173 }
174 174 }
175 175 catch(final IOException ioException) {
176   - fail("unable to deserialize object" + ioException);
  176 + failException("unable to deserialize object.", ioException);
177 177 }
178 178 catch(final ClassNotFoundException classNotFoundException) {
179   - fail("unable to deserialize object" + classNotFoundException);
  179 + failException("unable to deserialize object.", classNotFoundException);
180 180 }
181 181 finally {
182 182 try{
183 183 inputStream.close();
184 184 }
185 185 catch(final IOException ioException) {
186   - fail("failed to close output stream while serializing object" + ioException);
  186 + failException("failed to close output stream while serializing object.", ioException);
187 187 }
188 188 }
189 189
  190 + assertTrue("Deserialized (non-null) object is null!", o != null);
  191 +
190 192 @SuppressWarnings("unchecked")
191   - T t = (T)tclass.cast(o);
  193 + final T t = (T)tclass.cast(o);
  194 +
  195 + assertTrue("Deserialized instance should not be the same instance as the pre-serialization",
  196 + t != input);
  197 +
192 198 return t;
193 199
194 200 }

0 comments on commit 17e18fe

Please sign in to comment.
Something went wrong with that request. Please try again.