Merge lp:~pbeaman/akiban-persistit/fix-1073357-Value-getType into lp:akiban-persistit
- fix-1073357-Value-getType
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Peter Beaman | ||||||||
Approved revision: | 392 | ||||||||
Merged at revision: | 387 | ||||||||
Proposed branch: | lp:~pbeaman/akiban-persistit/fix-1073357-Value-getType | ||||||||
Merge into: | lp:akiban-persistit | ||||||||
Diff against target: |
838 lines (+226/-528) 4 files modified
src/main/java/com/persistit/Key.java (+22/-0) src/main/java/com/persistit/Value.java (+74/-3) src/test/java/com/persistit/unit/KeyTest1.java (+25/-0) src/test/java/com/persistit/unit/ValueTest4.java (+105/-525) |
||||||||
To merge this branch: | bzr merge lp:~pbeaman/akiban-persistit/fix-1073357-Value-getType | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Akiban Build User | Needs Fixing | ||
Nathan Williams | Approve | ||
Review via email: mp+132758@code.launchpad.net |
Commit message
Description of the change
Fixes bug https:/
The Value object encodes object graphs in which possibly may include cycles. To do so it encodes the any reference to an object that has already been serialized into the value as a special "REREF" item with a reference handle. However the Value#getType() method did not follow the handle to the referenced object to determine its class. This proposal corrects that behavior and adds tests for it.
This branch also adds two convenience methods:
Value#skipNull
Key#skipNull
Each of these is equivalent to the corresponding class' isNull method, but if the field is detected to be null the field cursor is advanced to the next field. For example, Key#skipNull is equivalent to
if (key.isNull()) {
key.
return true;
} else {
return false;
}
These are intended to satisfy a need first identified by the server team and are intended to simplify coding in some use cases.
Peter Beaman (pbeaman) wrote : | # |
Yuval Shavit (yshavit) wrote : | # |
I mentioned this in person to Peter, but it'd be nice to rename skipNull to isNullSkip or such. That way, the two methods would appear next to each other in IDEs with autocomplete. Not only would that be convenient, but it would also serve as a warning to anyone who (as many people do) navigates an API via autocomplete. Such a programmer would see these two similarly-named methods, and hopefully think, "hm, I should read what the distinction is."
As a slight variant, what about two overloads of isNull? One is isNull(boolean skipIfNull), the other is isNull() { return isNull(false); }. I merely mention that as a way of getting the same benefits (easy to find, autocomplete-
Peter Beaman (pbeaman) wrote : | # |
Good idea, done. The method is now
isNull(boolean skipNull)
Yuval Shavit (yshavit) wrote : | # |
Cool. I don't feel I'm qualified to comment on the rest of the merge prop, though if you'd like me to I can take a stab at it.
One comment on the test, lines 676-7, I believe the original bug was when the two objects were == (not just equal). So maybe create a new Long and then insert it twice, rather than inserting two unique Longs?
Nathan Williams (nwilliams) wrote : | # |
Looks mostly fine.
What if valueCache() does not contain the object? I'm not terribly familiar with it, but it looks like that is filled lazily. For example, what about Value append(a), append(b), append(a), store, clear, fetch, skip, skip, getType?
Peter Beaman (pbeaman) wrote : | # |
getValueCache() always returns a ValueCache instance, but that instance may be hollow. If it is hollow, the code throws an ISE. It's an illegal state because the only way to traverse a CLASS_REREF field is from the left, and therefore the referent should have been loaded first.
Peter Beaman (pbeaman) wrote : | # |
Unless you skip the field, like you said... As usual I responded without reading your comment carefully enough.
Peter Beaman (pbeaman) wrote : | # |
Modified further so that both get() and getType() correct return the value or type of the skipped field. See com.persistit.
Thanks for identifying this issue.
Nathan Williams (nwilliams) wrote : | # |
Looks plausible. And who am I to argue with passing tests.
Akiban Build User (build-akiban) wrote : | # |
There were 2 failures during build/test:
* job persistit-build failed at build number 473: http://
* view must-pass failed: persistit-build is yellow
Peter Beaman (pbeaman) wrote : | # |
An InUseException which may be either (a) weird I/O on the test machine, or (b) a bug I'm currently trying to track down in the stress tests. At any rate, the failure is unrelated to the code changes so I am re-Approving.
Preview Diff
1 | === modified file 'src/main/java/com/persistit/Key.java' | |||
2 | --- src/main/java/com/persistit/Key.java 2012-10-22 14:25:58 +0000 | |||
3 | +++ src/main/java/com/persistit/Key.java 2012-11-06 17:54:23 +0000 | |||
4 | @@ -3108,6 +3108,28 @@ | |||
5 | 3108 | } | 3108 | } |
6 | 3109 | 3109 | ||
7 | 3110 | /** | 3110 | /** |
8 | 3111 | * Determine if the current segment would return <code>null</code> if | ||
9 | 3112 | * {@link #decode()} were called. As a side effect, if <code>skipNull</code> | ||
10 | 3113 | * is true and the segment does encode a <code>null</code> value, then the | ||
11 | 3114 | * index is advanced to the beginning of the next segment. | ||
12 | 3115 | * | ||
13 | 3116 | * @param skipNull | ||
14 | 3117 | * whether to advance the index past a null segment value | ||
15 | 3118 | * @return <code>true</code> if the current segment is null, | ||
16 | 3119 | * <code>false</code> otherwise. | ||
17 | 3120 | */ | ||
18 | 3121 | public boolean isNull(final boolean skipNull) { | ||
19 | 3122 | if (getTypeCode() == TYPE_NULL) { | ||
20 | 3123 | if (skipNull) { | ||
21 | 3124 | _index = decodeEnd(_index + 1); | ||
22 | 3125 | } | ||
23 | 3126 | return true; | ||
24 | 3127 | } else { | ||
25 | 3128 | return false; | ||
26 | 3129 | } | ||
27 | 3130 | } | ||
28 | 3131 | |||
29 | 3132 | /** | ||
30 | 3111 | * Advance the index to the beginning of the next key segment. If the index | 3133 | * Advance the index to the beginning of the next key segment. If the index |
31 | 3112 | * is already at the end of the key, then wrap it to the beginning and | 3134 | * is already at the end of the key, then wrap it to the beginning and |
32 | 3113 | * return -1. | 3135 | * return -1. |
33 | 3114 | 3136 | ||
34 | === modified file 'src/main/java/com/persistit/Value.java' | |||
35 | --- src/main/java/com/persistit/Value.java 2012-09-25 21:00:18 +0000 | |||
36 | +++ src/main/java/com/persistit/Value.java 2012-11-06 17:54:23 +0000 | |||
37 | @@ -963,6 +963,30 @@ | |||
38 | 963 | return getTypeHandle() == TYPE_NULL; | 963 | return getTypeHandle() == TYPE_NULL; |
39 | 964 | } | 964 | } |
40 | 965 | 965 | ||
41 | 966 | /** | ||
42 | 967 | * Determine whether the data held by this <code>Value</code> is null. As a | ||
43 | 968 | * side effect, if <code>skipNull</code> is true and <a | ||
44 | 969 | * href="#_streamMode">Stream Mode</a> is enabled this method also advances | ||
45 | 970 | * the cursor to the next field if the current field is null. | ||
46 | 971 | * | ||
47 | 972 | * @param skipNull | ||
48 | 973 | * if <code>true</code>, the <code>Value</code> is in stream mode | ||
49 | 974 | * and the current field is null, then advance the cursor to next | ||
50 | 975 | * field | ||
51 | 976 | * @return <code>true</code> if the current state of this <code>Value</code> | ||
52 | 977 | * represents <i>null</i>. | ||
53 | 978 | */ | ||
54 | 979 | public boolean isNull(final boolean skipNull) { | ||
55 | 980 | if (isNull()) { | ||
56 | 981 | if (skipNull && _depth > 0) { | ||
57 | 982 | _next++; | ||
58 | 983 | } | ||
59 | 984 | return true; | ||
60 | 985 | } else { | ||
61 | 986 | return false; | ||
62 | 987 | } | ||
63 | 988 | } | ||
64 | 989 | |||
65 | 966 | boolean isAntiValue() { | 990 | boolean isAntiValue() { |
66 | 967 | return getTypeHandle() == CLASS_ANTIVALUE; | 991 | return getTypeHandle() == CLASS_ANTIVALUE; |
67 | 968 | } | 992 | } |
68 | @@ -1574,7 +1598,15 @@ | |||
69 | 1574 | final int saveEnd = _end; | 1598 | final int saveEnd = _end; |
70 | 1575 | try { | 1599 | try { |
71 | 1576 | final int classHandle = nextType(); | 1600 | final int classHandle = nextType(); |
73 | 1577 | if (classHandle > 0 && classHandle < CLASSES.length && CLASSES[classHandle] != null) { | 1601 | if (classHandle == CLASS_REREF) { |
74 | 1602 | final int base = _bytes[_next++] & 0xFF; | ||
75 | 1603 | final int handle = decodeVariableLengthInt(base); | ||
76 | 1604 | final Object object = getValueCache().get(handle); | ||
77 | 1605 | if (object == null) { | ||
78 | 1606 | throw new IllegalStateException("Reference to handle " + handle + " has no value"); | ||
79 | 1607 | } | ||
80 | 1608 | return object.getClass(); | ||
81 | 1609 | } else if (classHandle > 0 && classHandle < CLASSES.length && CLASSES[classHandle] != null) { | ||
82 | 1578 | return CLASSES[classHandle]; | 1610 | return CLASSES[classHandle]; |
83 | 1579 | } else if (classHandle == CLASS_ARRAY) { | 1611 | } else if (classHandle == CLASS_ARRAY) { |
84 | 1580 | _depth++; | 1612 | _depth++; |
85 | @@ -3956,8 +3988,12 @@ | |||
86 | 3956 | * to be decoded and constructed. | 3988 | * to be decoded and constructed. |
87 | 3957 | */ | 3989 | */ |
88 | 3958 | public void skip() { | 3990 | public void skip() { |
90 | 3959 | if (_depth == 0) | 3991 | if (_depth == 0) { |
91 | 3960 | return; | 3992 | return; |
92 | 3993 | } | ||
93 | 3994 | final int currentHandle = _serializedItemCount++; | ||
94 | 3995 | final int saveNext = _next; | ||
95 | 3996 | final int saveEnd = _end; | ||
96 | 3961 | final int classHandle = nextType(); | 3997 | final int classHandle = nextType(); |
97 | 3962 | if (classHandle == 0) | 3998 | if (classHandle == 0) |
98 | 3963 | return; | 3999 | return; |
99 | @@ -3973,6 +4009,7 @@ | |||
100 | 3973 | if (size >= 0) { | 4009 | if (size >= 0) { |
101 | 3974 | _next += size; | 4010 | _next += size; |
102 | 3975 | } else { | 4011 | } else { |
103 | 4012 | getValueCache().put(currentHandle, new SkippedFieldMarker(this, saveNext, saveEnd)); | ||
104 | 3976 | closeVariableLengthItem(); | 4013 | closeVariableLengthItem(); |
105 | 3977 | } | 4014 | } |
106 | 3978 | } | 4015 | } |
107 | @@ -5015,7 +5052,12 @@ | |||
108 | 5015 | * @return The object | 5052 | * @return The object |
109 | 5016 | */ | 5053 | */ |
110 | 5017 | Object get(final int handle) { | 5054 | Object get(final int handle) { |
112 | 5018 | return _array[handle]; | 5055 | Object object = _array[handle]; |
113 | 5056 | if (object instanceof SkippedFieldMarker) { | ||
114 | 5057 | object = ((SkippedFieldMarker) object).get(); | ||
115 | 5058 | _array[handle] = object; | ||
116 | 5059 | } | ||
117 | 5060 | return object; | ||
118 | 5019 | } | 5061 | } |
119 | 5020 | 5062 | ||
120 | 5021 | /** | 5063 | /** |
121 | @@ -5078,6 +5120,35 @@ | |||
122 | 5078 | } | 5120 | } |
123 | 5079 | } | 5121 | } |
124 | 5080 | 5122 | ||
125 | 5123 | private static class SkippedFieldMarker { | ||
126 | 5124 | final Value _value; | ||
127 | 5125 | final int _next; | ||
128 | 5126 | final int _end; | ||
129 | 5127 | |||
130 | 5128 | private SkippedFieldMarker(final Value value, final int next, final int end) { | ||
131 | 5129 | _value = value; | ||
132 | 5130 | _next = next; | ||
133 | 5131 | _end = end; | ||
134 | 5132 | } | ||
135 | 5133 | |||
136 | 5134 | private Object get() { | ||
137 | 5135 | final int saveDepth = _value._depth; | ||
138 | 5136 | final int saveLevel = _value._level; | ||
139 | 5137 | final int saveNext = _value._next; | ||
140 | 5138 | final int saveEnd = _value._end; | ||
141 | 5139 | try { | ||
142 | 5140 | _value._next = _next; | ||
143 | 5141 | _value._end = _end; | ||
144 | 5142 | return _value.get(); | ||
145 | 5143 | } finally { | ||
146 | 5144 | _value._end = saveEnd; | ||
147 | 5145 | _value._next = saveNext; | ||
148 | 5146 | _value._level = saveLevel; | ||
149 | 5147 | _value._depth = saveDepth; | ||
150 | 5148 | } | ||
151 | 5149 | } | ||
152 | 5150 | } | ||
153 | 5151 | |||
154 | 5081 | static class Version { | 5152 | static class Version { |
155 | 5082 | private final long _versionHandle; | 5153 | private final long _versionHandle; |
156 | 5083 | private final long _commitTimestamp; | 5154 | private final long _commitTimestamp; |
157 | 5084 | 5155 | ||
158 | === modified file 'src/test/java/com/persistit/unit/KeyTest1.java' | |||
159 | --- src/test/java/com/persistit/unit/KeyTest1.java 2012-10-22 14:25:58 +0000 | |||
160 | +++ src/test/java/com/persistit/unit/KeyTest1.java 2012-11-06 17:54:23 +0000 | |||
161 | @@ -703,6 +703,31 @@ | |||
162 | 703 | } | 703 | } |
163 | 704 | 704 | ||
164 | 705 | @Test | 705 | @Test |
165 | 706 | public void testSkipNull() { | ||
166 | 707 | final Key key1 = new Key(_persistit); | ||
167 | 708 | key1.clear().append(null).append(1).append(2).append(null).append(null).append(5); | ||
168 | 709 | key1.reset(); | ||
169 | 710 | assertTrue("seg0 is null: " + key1, key1.isNull(true)); | ||
170 | 711 | assertFalse("seg1 is not null: " + key1, key1.isNull(true)); | ||
171 | 712 | assertEquals("expect seg1 value", 1, key1.decode()); | ||
172 | 713 | assertFalse("seg2 is not null: " + key1, key1.isNull(true)); | ||
173 | 714 | assertEquals("expect seg2 value", 2, key1.decode()); | ||
174 | 715 | assertTrue("seg3 is null: " + key1, key1.isNull(true)); | ||
175 | 716 | assertTrue("seg4 is null: " + key1, key1.isNull(true)); | ||
176 | 717 | assertFalse("seg5 is not null:" + key1, key1.isNull(true)); | ||
177 | 718 | assertFalse("seg5 is not null:" + key1, key1.isNull(true)); | ||
178 | 719 | assertFalse("seg5 is not null:" + key1, key1.isNull(true)); | ||
179 | 720 | assertEquals("expect seg5 value", 5, key1.decodeInt()); | ||
180 | 721 | |||
181 | 722 | try { | ||
182 | 723 | key1.isNull(true); | ||
183 | 724 | Assert.fail("Expected MissingKeySegmentException!"); | ||
184 | 725 | } catch (final MissingKeySegmentException e) { | ||
185 | 726 | // expected | ||
186 | 727 | } | ||
187 | 728 | } | ||
188 | 729 | |||
189 | 730 | @Test | ||
190 | 706 | public void testFirstUniqueSegmentDepth() { | 731 | public void testFirstUniqueSegmentDepth() { |
191 | 707 | final Key key1 = new Key(_persistit); | 732 | final Key key1 = new Key(_persistit); |
192 | 708 | final Key key2 = new Key(_persistit); | 733 | final Key key2 = new Key(_persistit); |
193 | 709 | 734 | ||
194 | === modified file 'src/test/java/com/persistit/unit/ValueTest4.java' | |||
195 | --- src/test/java/com/persistit/unit/ValueTest4.java 2012-08-24 13:57:19 +0000 | |||
196 | +++ src/test/java/com/persistit/unit/ValueTest4.java 2012-11-06 17:54:23 +0000 | |||
197 | @@ -18,536 +18,116 @@ | |||
198 | 18 | import static org.junit.Assert.assertEquals; | 18 | import static org.junit.Assert.assertEquals; |
199 | 19 | import static org.junit.Assert.assertTrue; | 19 | import static org.junit.Assert.assertTrue; |
200 | 20 | 20 | ||
201 | 21 | import java.io.Externalizable; | ||
202 | 22 | import java.io.IOException; | ||
203 | 23 | import java.io.ObjectInput; | ||
204 | 24 | import java.io.ObjectInputStream; | ||
205 | 25 | import java.io.ObjectOutput; | ||
206 | 26 | import java.io.ObjectOutputStream; | ||
207 | 27 | import java.io.ObjectStreamException; | ||
208 | 28 | import java.io.ObjectStreamField; | ||
209 | 29 | import java.io.Serializable; | ||
210 | 30 | import java.util.ArrayList; | ||
211 | 31 | |||
212 | 32 | import org.junit.Test; | 21 | import org.junit.Test; |
213 | 33 | 22 | ||
214 | 34 | import com.persistit.DefaultCoderManager; | ||
215 | 35 | import com.persistit.DefaultValueCoder; | ||
216 | 36 | import com.persistit.Exchange; | ||
217 | 37 | import com.persistit.Persistit; | ||
218 | 38 | import com.persistit.PersistitUnitTestCase; | 23 | import com.persistit.PersistitUnitTestCase; |
219 | 39 | import com.persistit.Value; | 24 | import com.persistit.Value; |
220 | 40 | import com.persistit.encoding.CoderContext; | ||
221 | 41 | import com.persistit.encoding.CoderManager; | ||
222 | 42 | import com.persistit.encoding.SerialValueCoder; | ||
223 | 43 | import com.persistit.encoding.ValueCoder; | ||
224 | 44 | import com.persistit.exception.PersistitException; | ||
225 | 45 | 25 | ||
226 | 46 | public class ValueTest4 extends PersistitUnitTestCase { | 26 | public class ValueTest4 extends PersistitUnitTestCase { |
227 | 47 | 27 | ||
733 | 48 | /** | 28 | private final static String ABC = "abc"; |
734 | 49 | * Tests JSA 1.1 default serialization. Requires the | 29 | |
735 | 50 | * enableCompatibleConstructors to be true. | 30 | @Test |
736 | 51 | */ | 31 | public void streamMode() throws Exception { |
737 | 52 | Exchange _exchange; | 32 | final Value value = new Value(_persistit); |
738 | 53 | 33 | value.setStreamMode(true); | |
739 | 54 | public static class CustomSet extends ArrayList { | 34 | value.put(1); |
740 | 55 | private final static long serialVersionUID = 1L; | 35 | value.put(2f); |
741 | 56 | } | 36 | value.put(ABC); |
742 | 57 | 37 | value.put(ABC); | |
743 | 58 | private static class T implements Serializable { | 38 | value.put("xxabc".substring(2)); |
744 | 59 | private final static long serialVersionUID = 1L; | 39 | value.put(new Long(5)); |
745 | 60 | 40 | value.put(new Long(5)); | |
746 | 61 | private String _a; | 41 | value.setStreamMode(false); |
747 | 62 | private String _b; | 42 | value.setStreamMode(true); |
748 | 63 | 43 | assertEquals("expect primitive int class", int.class, value.getType()); | |
749 | 64 | private T(final String a, final String b) { | 44 | assertEquals("expect value", 1, value.get()); |
750 | 65 | _a = a; | 45 | assertEquals("expect primitive float class", float.class, value.getType()); |
751 | 66 | _b = b; | 46 | assertEquals("expect value", 2f, value.get()); |
752 | 67 | } | 47 | assertEquals("expect String class", String.class, value.getType()); |
753 | 68 | 48 | final String s1 = (String) value.get(); | |
754 | 69 | private T(final String a, final String b, final boolean f) { | 49 | assertEquals("expect String class", String.class, value.getType()); |
755 | 70 | _a = a; | 50 | final String s2 = (String) value.get(); |
756 | 71 | _b = b; | 51 | assertEquals("expect String class", String.class, value.getType()); |
757 | 72 | assertTrue("T 3-arg constructor should not be called", false); | 52 | final String s3 = (String) value.get(); |
758 | 73 | } | 53 | assertEquals("expect value", ABC, s1); |
759 | 74 | 54 | assertEquals("expect value", ABC, s2); | |
760 | 75 | private T(final int x, final boolean y, final String z) { | 55 | assertEquals("expect value", ABC, s3); |
761 | 76 | assertTrue("T 3-arg constructor should not be called", false); | 56 | assertEquals("expect Long class", Long.class, value.getType()); |
762 | 77 | } | 57 | final Long l1 = (Long) value.get(); |
763 | 78 | 58 | assertEquals("expect Long class", Long.class, value.getType()); | |
764 | 79 | @Override | 59 | final Long l2 = (Long) value.get(); |
765 | 80 | public String toString() { | 60 | assertEquals("expect equal values", l1, l2); |
766 | 81 | return "T:" + _a + _b; | 61 | assertTrue("encoding of primitive wrapper classes loses identity", l1 == l2); |
767 | 82 | } | 62 | assertTrue("interned constant \"abc\" has same identity", s1 == s2); |
768 | 83 | } | 63 | assertTrue("computed object \"xxabc\".substring(2) has different identity", s1 != s3); |
769 | 84 | 64 | } | |
770 | 85 | private static class TT extends T { | 65 | |
771 | 86 | private final static long serialVersionUID = 1L; | 66 | @Test |
772 | 87 | 67 | public void streamModeSkipNull() throws Exception { | |
773 | 88 | private TT(final String a, final String b) { | 68 | final Value value = new Value(_persistit); |
774 | 89 | super(a, b); | 69 | value.setStreamMode(true); |
775 | 90 | } | 70 | value.put(1); |
776 | 91 | 71 | value.put(2); | |
777 | 92 | private TT(final String a, final String b, final boolean f) { | 72 | value.put(null); |
778 | 93 | super(a, b, f); | 73 | value.put(4); |
779 | 94 | } | 74 | value.put(null); |
780 | 95 | 75 | value.put(null); | |
781 | 96 | private TT(final int x, final boolean y, final String z) { | 76 | value.put(null); |
782 | 97 | super(x, y, z); | 77 | value.put(8); |
783 | 98 | } | 78 | value.setStreamMode(false); |
784 | 99 | 79 | value.setStreamMode(true); | |
785 | 100 | @Override | 80 | assertEquals("expected value of field 1", 1, value.get()); |
786 | 101 | public String toString() { | 81 | assertEquals("expected value of field 2", 2, value.get()); |
787 | 102 | return "T" + super.toString(); | 82 | assertTrue("field 3 is null, don't advance cursor", value.isNull()); |
788 | 103 | } | 83 | assertTrue("field 3 is null, don't advance cursor", value.isNull()); |
789 | 104 | } | 84 | assertTrue("field 3 is null, don't advance cursor", value.isNull()); |
790 | 105 | 85 | assertTrue("field 3 is null, do advance cursor", value.isNull(true)); | |
791 | 106 | private static class TTT extends TT { | 86 | assertTrue("should be field 4", !value.isNull()); |
792 | 107 | private final static long serialVersionUID = 1L; | 87 | assertTrue("should be field 4", !value.isNull(true)); |
793 | 108 | 88 | assertEquals("expected value of field 4", 4, value.getInt()); | |
794 | 109 | private TTT(final String a, final String b) { | 89 | assertTrue("field 5 should be null", value.isNull(true)); |
795 | 110 | super(a, b); | 90 | assertTrue("field 6 should be null", value.isNull(true)); |
796 | 111 | assertTrue(a != null); | 91 | assertTrue("field 7 should be null", value.isNull(true)); |
797 | 112 | } | 92 | assertTrue("field 8 should not be null", !value.isNull(true)); |
798 | 113 | 93 | assertTrue("field 8 should not be null", !value.isNull(true)); | |
799 | 114 | private TTT(final String a, final String b, final boolean f) { | 94 | assertTrue("field 8 should not be null", !value.isNull(true)); |
800 | 115 | super(a, b, f); | 95 | assertTrue("field 8 should not be null", !value.isNull(true)); |
801 | 116 | assertTrue(a != null); | 96 | assertEquals("expected value of field 8", 8, value.get()); |
802 | 117 | } | 97 | } |
803 | 118 | 98 | ||
804 | 119 | private TTT(final int x, final boolean y, final String z) { | 99 | @Test |
805 | 120 | super(x, y, z); | 100 | public void streamModeGetAfterSkip() throws Exception { |
806 | 121 | } | 101 | final Value value = new Value(_persistit); |
807 | 122 | 102 | value.setStreamMode(true); | |
808 | 123 | @Override | 103 | // All same instance due to constant intern |
809 | 124 | public String toString() { | 104 | value.put(ABC); |
810 | 125 | return "T" + super.toString(); | 105 | value.put(2); |
811 | 126 | } | 106 | value.put(ABC); |
812 | 127 | 107 | value.put(4); | |
813 | 128 | } | 108 | value.put(ABC); |
814 | 129 | 109 | value.put(6); | |
815 | 130 | private static class TTTValueCoder extends DefaultValueCoder { | 110 | value.put(ABC); |
816 | 131 | static int _getCounter; | 111 | value.put(8); |
817 | 132 | 112 | value.put(ABC); | |
818 | 133 | TTTValueCoder(final Persistit persistit) { | 113 | value.put(ABC); |
819 | 134 | super(persistit, TTT.class); | 114 | value.put(ABC); |
820 | 135 | } | 115 | value.setStreamMode(false); |
821 | 136 | 116 | value.setStreamMode(true); | |
822 | 137 | @Override | 117 | value.skip(); // "abc" |
823 | 138 | public Object get(final Value value, final Class clazz, final CoderContext context) { | 118 | assertEquals("expect 2", 2, value.getInt()); |
824 | 139 | _getCounter++; | 119 | value.skip(); // "abc" |
825 | 140 | final TTT ttt = new TTT("x", "y"); | 120 | assertEquals("expect 2", 4, value.getInt()); |
826 | 141 | value.registerEncodedObject(ttt); | 121 | |
827 | 142 | render(value, ttt, clazz, context); | 122 | assertEquals("Field 5 should be a String", String.class, value.getType()); |
828 | 143 | return ttt; | 123 | final String s5 = value.getString(); |
829 | 144 | } | 124 | assertEquals("expect value", ABC, s5); |
830 | 145 | } | 125 | |
831 | 146 | 126 | assertEquals("expect 6", 6, value.getInt()); | |
832 | 147 | private static class S implements Serializable { | 127 | |
833 | 148 | String _a; | 128 | assertEquals("Field 7 should be a String", String.class, value.getType()); |
834 | 149 | String _b; | 129 | final String s7 = value.getString(); |
835 | 150 | 130 | assertTrue("expect identical", s5 == s7); | |
836 | 151 | private final static long serialVersionUID = 1L; | 131 | |
837 | 152 | 132 | } | |
333 | 153 | public void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException { | ||
334 | 154 | ois.defaultReadObject(); | ||
335 | 155 | } | ||
336 | 156 | |||
337 | 157 | public void writeObject(final ObjectOutputStream oos) throws IOException { | ||
338 | 158 | oos.defaultWriteObject(); | ||
339 | 159 | } | ||
340 | 160 | |||
341 | 161 | @Override | ||
342 | 162 | public String toString() { | ||
343 | 163 | return "S:" + _a + _b; | ||
344 | 164 | } | ||
345 | 165 | } | ||
346 | 166 | |||
347 | 167 | private static class SS extends S { | ||
348 | 168 | private final static long serialVersionUID = 1L; | ||
349 | 169 | |||
350 | 170 | private final String _c; | ||
351 | 171 | private final String _d; | ||
352 | 172 | protected String _ff; | ||
353 | 173 | |||
354 | 174 | private SS(final String c, final String d) { | ||
355 | 175 | _c = c; | ||
356 | 176 | _d = d; | ||
357 | 177 | _ff = "Final field"; | ||
358 | 178 | } | ||
359 | 179 | |||
360 | 180 | @Override | ||
361 | 181 | public String toString() { | ||
362 | 182 | return "S" + super.toString() + _c + _d; | ||
363 | 183 | } | ||
364 | 184 | } | ||
365 | 185 | |||
366 | 186 | private static class SSS extends SS { | ||
367 | 187 | private final static long serialVersionUID = 1L; | ||
368 | 188 | |||
369 | 189 | R _e; | ||
370 | 190 | private final W _f; | ||
371 | 191 | |||
372 | 192 | private SSS(final String c, final String d, final boolean e, final int f) { | ||
373 | 193 | super(c, d); | ||
374 | 194 | _e = new R(e); | ||
375 | 195 | _f = new W(f); | ||
376 | 196 | } | ||
377 | 197 | |||
378 | 198 | @Override | ||
379 | 199 | public String toString() { | ||
380 | 200 | return "S" + super.toString() + _e + _f; | ||
381 | 201 | |||
382 | 202 | } | ||
383 | 203 | } | ||
384 | 204 | |||
385 | 205 | private static class SSSS extends SSS { | ||
386 | 206 | private final static long serialVersionUID = 1L; | ||
387 | 207 | |||
388 | 208 | private String _g; | ||
389 | 209 | private String _h; | ||
390 | 210 | |||
391 | 211 | private SSSS() { | ||
392 | 212 | super("SSSS-c", "SSSS-d", true, 42); | ||
393 | 213 | _g = "Field g"; | ||
394 | 214 | _h = "Field h"; | ||
395 | 215 | } | ||
396 | 216 | |||
397 | 217 | private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("_g", String.class), }; | ||
398 | 218 | |||
399 | 219 | @Override | ||
400 | 220 | public String toString() { | ||
401 | 221 | return "S" + super.toString() + _g + _h + _ff; | ||
402 | 222 | } | ||
403 | 223 | } | ||
404 | 224 | |||
405 | 225 | private static class R implements Serializable { | ||
406 | 226 | private final static long serialVersionUID = 1L; | ||
407 | 227 | |||
408 | 228 | final static R R_TRUE = new R(true); | ||
409 | 229 | final static R R_FALSE = new R(false); | ||
410 | 230 | |||
411 | 231 | boolean _value; | ||
412 | 232 | |||
413 | 233 | R(final boolean b) { | ||
414 | 234 | _value = b; | ||
415 | 235 | } | ||
416 | 236 | |||
417 | 237 | public Object readResolve() throws ObjectStreamException { | ||
418 | 238 | return _value ? R_TRUE : R_FALSE; | ||
419 | 239 | } | ||
420 | 240 | |||
421 | 241 | @Override | ||
422 | 242 | public String toString() { | ||
423 | 243 | if (this == R_TRUE) { | ||
424 | 244 | return "true"; | ||
425 | 245 | } else if (this == R_FALSE) { | ||
426 | 246 | return "false"; | ||
427 | 247 | } else { | ||
428 | 248 | return "notReplaced"; | ||
429 | 249 | } | ||
430 | 250 | } | ||
431 | 251 | } | ||
432 | 252 | |||
433 | 253 | private static class W implements Serializable { | ||
434 | 254 | private final static long serialVersionUID = 1L; | ||
435 | 255 | |||
436 | 256 | int _value; | ||
437 | 257 | |||
438 | 258 | W(final int v) { | ||
439 | 259 | _value = v; | ||
440 | 260 | } | ||
441 | 261 | |||
442 | 262 | private Object writeReplace() throws ObjectStreamException { | ||
443 | 263 | return new WReplacement(_value); | ||
444 | 264 | } | ||
445 | 265 | |||
446 | 266 | @Override | ||
447 | 267 | public String toString() { | ||
448 | 268 | return "W:" + _value; | ||
449 | 269 | } | ||
450 | 270 | } | ||
451 | 271 | |||
452 | 272 | private static class WReplacement implements Serializable { | ||
453 | 273 | private final static long serialVersionUID = 1L; | ||
454 | 274 | |||
455 | 275 | int _value; | ||
456 | 276 | |||
457 | 277 | WReplacement(final int v) { | ||
458 | 278 | _value = v; | ||
459 | 279 | } | ||
460 | 280 | |||
461 | 281 | private Object readResolve() throws ObjectStreamException { | ||
462 | 282 | return new W(_value); | ||
463 | 283 | } | ||
464 | 284 | |||
465 | 285 | @Override | ||
466 | 286 | public String toString() { | ||
467 | 287 | return "WReplacement:" + _value; | ||
468 | 288 | } | ||
469 | 289 | |||
470 | 290 | } | ||
471 | 291 | |||
472 | 292 | private static class E implements Externalizable { | ||
473 | 293 | private final static long serialVersionUID = 1L; | ||
474 | 294 | String _a; | ||
475 | 295 | String _b; | ||
476 | 296 | |||
477 | 297 | public E() { | ||
478 | 298 | } | ||
479 | 299 | |||
480 | 300 | @Override | ||
481 | 301 | public void readExternal(final ObjectInput oi) throws IOException { | ||
482 | 302 | oi.readUTF(); // "foo" | ||
483 | 303 | _a = oi.readUTF(); | ||
484 | 304 | _b = oi.readUTF(); | ||
485 | 305 | } | ||
486 | 306 | |||
487 | 307 | @Override | ||
488 | 308 | public void writeExternal(final ObjectOutput oo) throws IOException { | ||
489 | 309 | oo.writeUTF("hello"); | ||
490 | 310 | oo.writeUTF(_a); | ||
491 | 311 | oo.writeUTF(_b); | ||
492 | 312 | } | ||
493 | 313 | |||
494 | 314 | @Override | ||
495 | 315 | public String toString() { | ||
496 | 316 | return "E:" + _a + _b; | ||
497 | 317 | } | ||
498 | 318 | } | ||
499 | 319 | |||
500 | 320 | private static class EE extends E { | ||
501 | 321 | private final static long serialVersionUID = 1L; | ||
502 | 322 | private final Thread _thread = Thread.currentThread(); // intentionally | ||
503 | 323 | |||
504 | 324 | // not | ||
505 | 325 | // Serializable | ||
506 | 326 | |||
507 | 327 | public EE() { | ||
508 | 328 | super(); | ||
509 | 329 | } | ||
510 | 330 | |||
511 | 331 | EE(final String a, final String b) { | ||
512 | 332 | _a = a; | ||
513 | 333 | _b = b; | ||
514 | 334 | } | ||
515 | 335 | |||
516 | 336 | @Override | ||
517 | 337 | public String toString() { | ||
518 | 338 | return "E" + super.toString() + (_thread != null ? "" : ""); | ||
519 | 339 | } | ||
520 | 340 | } | ||
521 | 341 | |||
522 | 342 | @Override | ||
523 | 343 | public void setUp() throws Exception { | ||
524 | 344 | super.setUp(); | ||
525 | 345 | _exchange = _persistit.getExchange("persistit", getClass().getSimpleName(), true); | ||
526 | 346 | } | ||
527 | 347 | |||
528 | 348 | @Override | ||
529 | 349 | public void tearDown() throws Exception { | ||
530 | 350 | _persistit.releaseExchange(_exchange); | ||
531 | 351 | _exchange = null; | ||
532 | 352 | super.tearDown(); | ||
533 | 353 | } | ||
534 | 354 | |||
535 | 355 | @Test | ||
536 | 356 | public void test1() throws PersistitException { | ||
537 | 357 | System.out.print("test1 "); | ||
538 | 358 | final S s = new S(); | ||
539 | 359 | s._a = "1"; | ||
540 | 360 | s._b = "2"; | ||
541 | 361 | _exchange.getValue().put(s); | ||
542 | 362 | _exchange.clear().append("test1").store(); | ||
543 | 363 | final Object x = _exchange.getValue().get(); | ||
544 | 364 | assertEquals("S:12", x.toString()); | ||
545 | 365 | System.out.println("- done"); | ||
546 | 366 | } | ||
547 | 367 | |||
548 | 368 | @Test | ||
549 | 369 | public void test2() throws PersistitException { | ||
550 | 370 | System.out.print("test2 "); | ||
551 | 371 | final SS ss = new SS("3", "4"); | ||
552 | 372 | ss._a = "1"; | ||
553 | 373 | ss._b = "2"; | ||
554 | 374 | _exchange.getValue().put(ss); | ||
555 | 375 | _exchange.clear().append("test2").store(); | ||
556 | 376 | final Object x = _exchange.getValue().get(); | ||
557 | 377 | assertEquals("SS:1234", x.toString()); | ||
558 | 378 | System.out.println("- done"); | ||
559 | 379 | } | ||
560 | 380 | |||
561 | 381 | @Test | ||
562 | 382 | public void test3() throws PersistitException { | ||
563 | 383 | System.out.print("test3 "); | ||
564 | 384 | final E e = new E(); | ||
565 | 385 | e._a = "1"; | ||
566 | 386 | e._b = "2"; | ||
567 | 387 | _exchange.getValue().put(e); | ||
568 | 388 | _exchange.clear().append("test3").store(); | ||
569 | 389 | final Object x = _exchange.getValue().get(); | ||
570 | 390 | assertEquals("E:12", x.toString()); | ||
571 | 391 | System.out.println("- done"); | ||
572 | 392 | } | ||
573 | 393 | |||
574 | 394 | @Test | ||
575 | 395 | public void test4() throws PersistitException { | ||
576 | 396 | System.out.print("test4 "); | ||
577 | 397 | final EE ee = new EE("6", "7"); | ||
578 | 398 | ee._a = "1"; | ||
579 | 399 | ee._b = "2"; | ||
580 | 400 | _exchange.getValue().put(ee); | ||
581 | 401 | _exchange.clear().append("test4").store(); | ||
582 | 402 | final Object x = _exchange.getValue().get(); | ||
583 | 403 | assertEquals("EE:12", x.toString()); | ||
584 | 404 | System.out.println("- done"); | ||
585 | 405 | } | ||
586 | 406 | |||
587 | 407 | @Test | ||
588 | 408 | public void test5() throws PersistitException { | ||
589 | 409 | System.out.print("test5 "); | ||
590 | 410 | final T t = new T("1", "2"); | ||
591 | 411 | _exchange.getValue().put(t); | ||
592 | 412 | _exchange.clear().append("test5").store(); | ||
593 | 413 | final Object x = _exchange.getValue().get(); | ||
594 | 414 | assertEquals("T:12", x.toString()); | ||
595 | 415 | System.out.println("- done"); | ||
596 | 416 | } | ||
597 | 417 | |||
598 | 418 | @Test | ||
599 | 419 | public void test6() throws PersistitException { | ||
600 | 420 | System.out.print("test6 "); | ||
601 | 421 | final TT tt = new TT("1", "2"); | ||
602 | 422 | _exchange.getValue().put(tt); | ||
603 | 423 | _exchange.clear().append("test6").store(); | ||
604 | 424 | final Object x = _exchange.getValue().get(); | ||
605 | 425 | assertEquals("TT:12", x.toString()); | ||
606 | 426 | System.out.println("- done"); | ||
607 | 427 | } | ||
608 | 428 | |||
609 | 429 | @Test | ||
610 | 430 | public void test7() throws PersistitException { | ||
611 | 431 | System.out.print("test7 "); | ||
612 | 432 | final CoderManager cm = _persistit.getCoderManager(); | ||
613 | 433 | cm.registerValueCoder(TTT.class, new TTTValueCoder(_persistit)); | ||
614 | 434 | TTTValueCoder._getCounter = 0; | ||
615 | 435 | final TTT ttt = new TTT("1", "2"); | ||
616 | 436 | _exchange.getValue().put(ttt); | ||
617 | 437 | _exchange.clear().append("test7").store(); | ||
618 | 438 | final Object x = _exchange.getValue().get(); | ||
619 | 439 | assertEquals("TTT:12", x.toString()); | ||
620 | 440 | assertEquals(1, TTTValueCoder._getCounter); | ||
621 | 441 | cm.unregisterValueCoder(TTT.class); | ||
622 | 442 | System.out.println("- done"); | ||
623 | 443 | } | ||
624 | 444 | |||
625 | 445 | @Test | ||
626 | 446 | public void test8() throws PersistitException { | ||
627 | 447 | System.out.print("test8 "); | ||
628 | 448 | final CoderManager cm = _persistit.getCoderManager(); | ||
629 | 449 | cm.registerValueCoder(TTT.class, new TTTValueCoder(_persistit)); | ||
630 | 450 | TTTValueCoder._getCounter = 0; | ||
631 | 451 | final TTT ttt = new TTT("1", "2"); | ||
632 | 452 | _exchange.getValue().put(ttt); | ||
633 | 453 | _exchange.clear().append("test8").store(); | ||
634 | 454 | final Object x = _exchange.getValue().get(); | ||
635 | 455 | assertEquals("TTT:12", x.toString()); | ||
636 | 456 | assertEquals(1, TTTValueCoder._getCounter); | ||
637 | 457 | cm.unregisterValueCoder(TTT.class); | ||
638 | 458 | System.out.println("- done"); | ||
639 | 459 | } | ||
640 | 460 | |||
641 | 461 | @Test | ||
642 | 462 | public void test9() throws PersistitException { | ||
643 | 463 | System.out.print("test9 "); | ||
644 | 464 | final SSS sss = new SSS("3", "4", true, 5); | ||
645 | 465 | sss._a = "1"; | ||
646 | 466 | sss._b = "2"; | ||
647 | 467 | _exchange.getValue().put(sss); | ||
648 | 468 | _exchange.clear().append("test9").store(); | ||
649 | 469 | final Object x = _exchange.getValue().get(); | ||
650 | 470 | assertEquals("SSS:1234trueW:5", x.toString()); | ||
651 | 471 | System.out.println("- done"); | ||
652 | 472 | } | ||
653 | 473 | |||
654 | 474 | @Test | ||
655 | 475 | public void test10() throws PersistitException { | ||
656 | 476 | System.out.print("test10 "); | ||
657 | 477 | final SSS sss = new SSS("3", "4", true, 5); | ||
658 | 478 | sss._a = "1"; | ||
659 | 479 | sss._b = "2"; | ||
660 | 480 | _exchange.getValue().put(sss); | ||
661 | 481 | _exchange.clear().append("test10").store(); | ||
662 | 482 | final Object x = _exchange.getValue().get(); | ||
663 | 483 | assertEquals("SSS:1234trueW:5", x.toString()); | ||
664 | 484 | System.out.println("- done"); | ||
665 | 485 | } | ||
666 | 486 | |||
667 | 487 | @Test | ||
668 | 488 | public void test11() throws PersistitException { | ||
669 | 489 | System.out.print("test11 "); | ||
670 | 490 | final SSSS ssss = new SSSS(); | ||
671 | 491 | ssss._a = "Field a"; | ||
672 | 492 | ssss._b = "Field b"; | ||
673 | 493 | ssss._g = "Field g"; | ||
674 | 494 | ssss._h = "Field h"; | ||
675 | 495 | _exchange.getValue().put(ssss); | ||
676 | 496 | _exchange.clear().append("test11").store(); | ||
677 | 497 | final Object x = _exchange.getValue().get(); | ||
678 | 498 | // assertEquals("SSSS:0000falsenull", x.toString()); | ||
679 | 499 | System.out.print(" x=" + x + " "); | ||
680 | 500 | System.out.println(); | ||
681 | 501 | System.out.println("Value: " + _exchange.getValue()); | ||
682 | 502 | System.out.println("- done"); | ||
683 | 503 | } | ||
684 | 504 | |||
685 | 505 | @Test | ||
686 | 506 | public void test12() throws PersistitException { | ||
687 | 507 | System.out.print("test12 "); | ||
688 | 508 | final CoderManager cm = _persistit.getCoderManager(); | ||
689 | 509 | final ValueCoder defaultCoder = cm.getValueCoder(SSSS.class); | ||
690 | 510 | _persistit.getCoderManager().registerValueCoder(SSSS.class, new SerialValueCoder(SSSS.class)); | ||
691 | 511 | final SSSS ssss = new SSSS(); | ||
692 | 512 | ssss._a = "Field a"; | ||
693 | 513 | ssss._b = "Field b"; | ||
694 | 514 | ssss._g = "Field g"; | ||
695 | 515 | ssss._h = "Field h"; | ||
696 | 516 | _exchange.getValue().put(ssss); | ||
697 | 517 | _exchange.clear().append("test12").store(); | ||
698 | 518 | final Object x = _exchange.getValue().get(); | ||
699 | 519 | // assertEquals("SSSS:0000falsenull", x.toString()); | ||
700 | 520 | System.out.print(" x=" + x + " "); | ||
701 | 521 | System.out.println(); | ||
702 | 522 | System.out.println("Value: " + _exchange.getValue()); | ||
703 | 523 | cm.registerValueCoder(SSSS.class, defaultCoder); | ||
704 | 524 | System.out.println("- done"); | ||
705 | 525 | } | ||
706 | 526 | |||
707 | 527 | public static void main(final String[] args) throws Exception { | ||
708 | 528 | new ValueTest4().initAndRunTest(); | ||
709 | 529 | } | ||
710 | 530 | |||
711 | 531 | @Override | ||
712 | 532 | public void runAllTests() throws Exception { | ||
713 | 533 | final CoderManager cm = _persistit.getCoderManager(); | ||
714 | 534 | _persistit.setCoderManager(new DefaultCoderManager(_persistit, "com.persistit.unit.ValueTest4$*")); | ||
715 | 535 | _exchange = _persistit.getExchange("persistit", "ValueTest4", true); | ||
716 | 536 | |||
717 | 537 | test1(); | ||
718 | 538 | test2(); | ||
719 | 539 | test3(); | ||
720 | 540 | test4(); | ||
721 | 541 | test5(); | ||
722 | 542 | test6(); | ||
723 | 543 | test7(); | ||
724 | 544 | test8(); | ||
725 | 545 | test9(); | ||
726 | 546 | test10(); | ||
727 | 547 | test11(); | ||
728 | 548 | test12(); | ||
729 | 549 | |||
730 | 550 | _persistit.setCoderManager(cm); | ||
731 | 551 | } | ||
732 | 552 | |||
838 | 553 | } | 133 | } |
Note: the majority of ValueTest4 was deleted because it was identical to ValueTest3.