Skip to content

Commit b64a334

Browse files
committed
Improve Writer's API for serializable objects
- Fix reference counting for serializable objects
1 parent 291905f commit b64a334

11 files changed

+263
-15
lines changed

Diff for: src/main/java/com/marcospassos/phpserializer/Writer.java

+31-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
package com.marcospassos.phpserializer;
33

44
import java.lang.reflect.Modifier;
5+
import java.util.function.Consumer;
6+
import com.marcospassos.phpserializer.state.FinishedState;
7+
import com.marcospassos.phpserializer.state.WritingSerializableObjectState;
58
import com.marcospassos.phpserializer.state.WritingValueState;
69

710
/**
@@ -18,14 +21,16 @@ public class Writer
1821
private StringBuffer buffer;
1922

2023
/**
21-
* The current state of the writer.
24+
* The reference counter.
2225
*/
23-
private WriterState state;
26+
private int pointer = 1;
2427

2528
/**
26-
* The reference counter.
29+
* The current state of the writer.
2730
*/
28-
private int pointer = 1;
31+
private WriterState state;
32+
33+
private Writer subWriter;
2934

3035
/**
3136
* Creates a new writer using an internal buffer.
@@ -60,21 +65,39 @@ public String getResult()
6065
* Writes a custom serialized object to the buffer.
6166
*
6267
* @param className The fully-qualified name of the class.
63-
* @param data The serialized data.
68+
*
69+
* @return A writer to be used to custom write the serializable object.
6470
*/
65-
public void writeObject(String className, String data)
71+
public Writer writeSerializableObjectStart(String className)
6672
{
67-
setState(state.value());
73+
setState(state.serializableBegin());
6874

6975
buffer.append("C:");
7076
buffer.append(className.length());
7177
buffer.append(":\"");
7278
buffer.append(className);
7379
buffer.append("\":");
80+
81+
subWriter = new Writer();
82+
83+
return subWriter;
84+
}
85+
86+
void writeSerializableObjectEnd() {
87+
setState(state.serializableEnd());
88+
89+
if (!(subWriter.state instanceof FinishedState)) {
90+
throw new IllegalStateException();
91+
}
92+
93+
String data = subWriter.getResult();
94+
7495
buffer.append(data.length());
7596
buffer.append(":{");
7697
buffer.append(data);
7798
buffer.append("}");
99+
100+
pointer += subWriter.getPointer();
78101
}
79102

80103
/**
@@ -336,7 +359,7 @@ public int getPointer()
336359
*
337360
* @param state The new state.
338361
*/
339-
private void setState(WriterState state)
362+
protected void setState(WriterState state)
340363
{
341364
if (state.isReferable()) {
342365
pointer++;

Diff for: src/main/java/com/marcospassos/phpserializer/WriterState.java

+22
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,28 @@ public interface WriterState
1818
*/
1919
boolean isReferable();
2020

21+
/**
22+
* Returns the new state generated as a result of transitions from the
23+
* current state to the new state.
24+
*
25+
* @return WriterState The new state.
26+
*
27+
* @throws IllegalStateException if the current state does not allow the
28+
* transition to the new state.
29+
*/
30+
WriterState serializableBegin();
31+
32+
/**
33+
* Returns the new state generated as a result of transitions from the
34+
* current state to the new state.
35+
*
36+
* @return WriterState The new state.
37+
*
38+
* @throws IllegalStateException if the current state does not allow the
39+
* transition to the new state.
40+
*/
41+
WriterState serializableEnd();
42+
2143
/**
2244
* Returns the new state generated as a result of transitions from the
2345
* current state to the new state.

Diff for: src/main/java/com/marcospassos/phpserializer/state/AbstractState.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,18 @@
1313
* @author Marcos Passos
1414
* @since 1.0
1515
*/
16-
public abstract class AbstractState implements WriterState
16+
abstract class AbstractState implements WriterState
1717
{
18+
public WriterState serializableBegin()
19+
{
20+
throw new IllegalStateException();
21+
}
22+
23+
public WriterState serializableEnd()
24+
{
25+
throw new IllegalStateException();
26+
}
27+
1828
public WriterState objectBegin()
1929
{
2030
throw new IllegalStateException();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
2+
package com.marcospassos.phpserializer.state;
3+
4+
import com.marcospassos.phpserializer.WriterState;
5+
6+
/**
7+
* Represents the state of the writer while writing an object.
8+
*
9+
* @author Marcos Passos
10+
* @since 1.0
11+
*/
12+
public class WritingSerializableObjectState extends AbstractState
13+
{
14+
/**
15+
* The parent state.
16+
*/
17+
WriterState parent;
18+
19+
/**
20+
* Creates a new state from the specified parent state.
21+
*
22+
* @param parent The parent state.
23+
*/
24+
public WritingSerializableObjectState(WriterState parent)
25+
{
26+
this.parent = parent;
27+
}
28+
29+
@Override
30+
public boolean isReferable()
31+
{
32+
return false;
33+
}
34+
35+
@Override
36+
public WriterState serializableEnd()
37+
{
38+
return parent;
39+
}
40+
}

Diff for: src/main/java/com/marcospassos/phpserializer/state/WritingValueState.java

+6
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ public boolean isReferable()
4040
return true;
4141
}
4242

43+
@Override
44+
public WriterState serializableBegin()
45+
{
46+
return new WritingSerializableObjectState(parent);
47+
}
48+
4349
@Override
4450
public WriterState objectBegin()
4551
{

Diff for: src/test/java/com/marcospassos/phpserializer/WriterTest.java

+18-2
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,25 @@ public void writeObject() throws Exception
3939
public void writeSerializableObject() throws Exception
4040
{
4141
Writer writer = new Writer();
42-
writer.writeObject("Foo", "i:1");
42+
Writer objectWriter = writer.writeSerializableObjectStart("Foo");
4343

44-
assertEquals("C:3:\"Foo\":3:{i:1}", writer.getResult());
44+
objectWriter.writeArrayStart(1);
45+
objectWriter.writeKey(0);
46+
objectWriter.writeString("bar");
47+
objectWriter.writeArrayEnd();
48+
49+
writer.writeSerializableObjectEnd();
50+
51+
assertEquals("C:3:\"Foo\":20:{a:1:{i:0;s:3:\"bar\";}}", writer.getResult());
52+
assertEquals(3, writer.getPointer());
53+
}
54+
55+
@Test(expected = IllegalStateException.class)
56+
public void writeSerializableObjectEndFailsIfNothingIsWritten() throws Exception
57+
{
58+
Writer writer = new Writer();
59+
writer.writeSerializableObjectStart("Foo");
60+
writer.writeSerializableObjectEnd();
4561
}
4662

4763
@Test

Diff for: src/test/java/com/marcospassos/phpserializer/state/EndStateTest.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
*/
1111
public class EndStateTest
1212
{
13-
1413
private FinishedState state = new FinishedState();
1514

1615
@Test
@@ -37,6 +36,18 @@ public void objectEndIsNotAllowed() throws Exception
3736
state.objectEnd();
3837
}
3938

39+
@Test(expected = IllegalStateException.class)
40+
public void serializableObjectBeginIsNotAllowed() throws Exception
41+
{
42+
state.serializableBegin();
43+
}
44+
45+
@Test(expected = IllegalStateException.class)
46+
public void serializableObjectEndIsNotAllowed() throws Exception
47+
{
48+
state.serializableEnd();
49+
}
50+
4051
@Test(expected = IllegalStateException.class)
4152
public void propertyIsNotAllowed() throws Exception
4253
{

Diff for: src/test/java/com/marcospassos/phpserializer/state/WritingArrayStateTest.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
public class WritingArrayStateTest
1717
{
18-
1918
private WritingArrayState state;
2019
private WriterState parent;
2120

@@ -50,6 +49,18 @@ public void objectEndIsNotAllowed() throws Exception
5049
state.objectEnd();
5150
}
5251

52+
@Test(expected = IllegalStateException.class)
53+
public void serializableObjectBeginIsNotAllowed() throws Exception
54+
{
55+
state.serializableBegin();
56+
}
57+
58+
@Test(expected = IllegalStateException.class)
59+
public void serializableObjectEndIsNotAllowed() throws Exception
60+
{
61+
state.serializableEnd();
62+
}
63+
5364
@Test(expected = IllegalStateException.class)
5465
public void propertyIsNotAllowed() throws Exception
5566
{

Diff for: src/test/java/com/marcospassos/phpserializer/state/WritingObjectStateTest.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
public class WritingObjectStateTest
1717
{
18-
1918
private WritingObjectState state;
2019
private WriterState parent;
2120

@@ -56,6 +55,18 @@ public void propertyIsAllowed() throws Exception
5655
assertTrue(state.property() instanceof WritingValueState);
5756
}
5857

58+
@Test(expected = IllegalStateException.class)
59+
public void serializableObjectBeginIsNotAllowed() throws Exception
60+
{
61+
state.serializableBegin();
62+
}
63+
64+
@Test(expected = IllegalStateException.class)
65+
public void serializableObjectEndIsNotAllowed() throws Exception
66+
{
67+
state.serializableEnd();
68+
}
69+
5970
@Test(expected = IllegalStateException.class)
6071
public void arrayBeginIsNotAllowed() throws Exception
6172
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.marcospassos.phpserializer.state;
2+
3+
import com.marcospassos.phpserializer.WriterState;
4+
import org.junit.Before;
5+
import org.junit.Test;
6+
7+
import static org.junit.Assert.assertFalse;
8+
import static org.junit.Assert.assertSame;
9+
import static org.junit.Assert.assertTrue;
10+
import static org.mockito.Mockito.mock;
11+
12+
/**
13+
* @author Marcos Passos
14+
* @since 1.0
15+
*/
16+
public class WritingSerializableObjectStateTest
17+
{
18+
private WritingSerializableObjectState state;
19+
private WriterState parent;
20+
21+
@Before
22+
public void setUp() throws Exception
23+
{
24+
parent = mock(WriterState.class);
25+
state = new WritingSerializableObjectState(parent);
26+
}
27+
28+
@Test
29+
public void isReferableReturnsFalse() throws Exception
30+
{
31+
assertFalse(state.isReferable());
32+
}
33+
34+
@Test(expected = IllegalStateException.class)
35+
public void serializableObjectBeginIsNotAllowed() throws Exception
36+
{
37+
state.serializableBegin();
38+
}
39+
40+
@Test
41+
public void serializableObjectEndIsAllowed() throws Exception
42+
{
43+
assertSame(parent, state.serializableEnd());
44+
}
45+
46+
@Test(expected = IllegalStateException.class)
47+
public void valueIsNotAllowed() throws Exception
48+
{
49+
state.value();
50+
}
51+
52+
@Test(expected = IllegalStateException.class)
53+
public void objectBeginIsNotAllowed() throws Exception
54+
{
55+
state.objectBegin();
56+
}
57+
58+
@Test(expected = IllegalStateException.class)
59+
public void objectEndIsNotAllowed() throws Exception
60+
{
61+
state.objectEnd();
62+
}
63+
64+
@Test(expected = IllegalStateException.class)
65+
public void propertyIsNotAllowed() throws Exception
66+
{
67+
state.property();
68+
}
69+
70+
@Test(expected = IllegalStateException.class)
71+
public void arrayBeginIsNotAllowed() throws Exception
72+
{
73+
state.arrayBegin();
74+
}
75+
76+
@Test(expected = IllegalStateException.class)
77+
public void arrayEndIsNotAllowed() throws Exception
78+
{
79+
state.arrayEnd();
80+
}
81+
82+
@Test(expected = IllegalStateException.class)
83+
public void keyIsNotAllowed() throws Exception
84+
{
85+
state.key();
86+
}
87+
}

0 commit comments

Comments
 (0)