Skip to content

Commit d7a1a0e

Browse files
Simple Lazy working quite well. More complex lazies are not implemented yet.
1 parent 2e1b839 commit d7a1a0e

8 files changed

Lines changed: 307 additions & 128 deletions

File tree

spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/lazy/SpringDataEclipseStoreLazy.java

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,40 @@
2222
import org.eclipse.serializer.reference.Swizzling;
2323

2424

25+
/**
26+
* This is the Lazy-Wrapper a user of the Spring-Data-Eclipse-Store-Library should use. Please <b>do not use the
27+
* {@link Lazy}-Wrapper!</b> Because SDES is making working copies of the stored data, the {@link Lazy} does not work as
28+
* expected. Instead, use this Wrapper. It brings the same functionality as the native {@link Lazy}-Wrapper but works
29+
* with working copies.
30+
*/
2531
public interface SpringDataEclipseStoreLazy<T> extends Lazy<T>
2632
{
2733
static <T> SpringDataEclipseStoreLazy.Default<T> build(final T objectToWrapInLazy)
2834
{
2935
return new Default<>(objectToWrapInLazy);
3036
}
3137

32-
static SpringDataEclipseStoreLazy.Default<?> buildOnlyForStorage(final long objectId)
33-
{
34-
return new Default<>(objectId);
35-
}
38+
SpringDataEclipseStoreLazy<T> copy();
3639

3740
long objectId();
3841

42+
/**
43+
* This class is very complex and its various membervariables all have their reason to exist. This code is very
44+
* difficult to read due to its the functionality explained in the {@link SpringDataEclipseStoreLazyBinaryHandler}.
45+
*
46+
* @param <T>
47+
*/
3948
class Default<T> implements SpringDataEclipseStoreLazy<T>
4049
{
50+
private T objectToBeWrapped;
4151
private Lazy<T> wrappedLazy;
4252
private long objectId = Swizzling.notFoundId();
4353
private transient ObjectSwizzling loader;
4454
private transient boolean isStored = false;
4555

4656
private Default(final T wrappedObject)
4757
{
48-
this.wrappedLazy = Lazy.Reference(wrappedObject);
58+
this.objectToBeWrapped = wrappedObject;
4959
}
5060

5161
private Default(final long objectId, final ObjectSwizzling loader)
@@ -54,11 +64,6 @@ private Default(final long objectId, final ObjectSwizzling loader)
5464
this.loader = loader;
5565
}
5666

57-
private Default(final long objectId)
58-
{
59-
this.objectId = objectId;
60-
}
61-
6267
private Lazy<T> ensureLazy()
6368
{
6469
if(this.wrappedLazy == null)
@@ -80,6 +85,10 @@ public static final Class<SpringDataEclipseStoreLazy.Default<?>> genericType()
8085
@Override
8186
public T get()
8287
{
88+
if(this.objectToBeWrapped != null)
89+
{
90+
return this.objectToBeWrapped;
91+
}
8392
return this.ensureLazy().get();
8493
}
8594

@@ -116,6 +125,10 @@ void setStored()
116125
@Override
117126
public boolean isLoaded()
118127
{
128+
if(this.objectToBeWrapped != null)
129+
{
130+
return true;
131+
}
119132
if(this.wrappedLazy == null)
120133
{
121134
return false;
@@ -148,5 +161,24 @@ public long objectId()
148161
}
149162
return this.objectId;
150163
}
164+
165+
void setWrappedLazy(final Lazy<T> wrappedLazy)
166+
{
167+
this.wrappedLazy = wrappedLazy;
168+
}
169+
170+
public T getObjectToBeWrapped()
171+
{
172+
return this.objectToBeWrapped;
173+
}
174+
175+
@Override
176+
public SpringDataEclipseStoreLazy<T> copy()
177+
{
178+
return new SpringDataEclipseStoreLazy.Default(
179+
this.objectId,
180+
this.loader
181+
);
182+
}
151183
}
152184
}

spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/lazy/SpringDataEclipseStoreLazyBinaryHandler.java

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
import java.lang.reflect.Constructor;
1919
import java.util.Objects;
2020

21+
import org.eclipse.serializer.memory.XMemory;
2122
import org.eclipse.serializer.persistence.binary.types.AbstractBinaryHandlerCustom;
2223
import org.eclipse.serializer.persistence.binary.types.Binary;
24+
import org.eclipse.serializer.persistence.binary.types.BinaryTypeHandler;
2325
import org.eclipse.serializer.persistence.types.PersistenceLoadHandler;
2426
import org.eclipse.serializer.persistence.types.PersistenceReferenceLoader;
2527
import org.eclipse.serializer.persistence.types.PersistenceStoreHandler;
@@ -29,67 +31,115 @@
2931

3032

3133
/**
32-
* Copied from
33-
* {@link org.eclipse.serializer.persistence.binary.org.eclipse.serializer.reference.BinaryHandlerLazyDefault}.
34+
* This is a complicated one. First off: this handler should only be used for WorkingCopies (see
35+
* {@link software.xdev.spring.data.eclipse.store.repository.support.copier.copier.EclipseSerializerRegisteringCopier})!
36+
* <p>
37+
* First case:<br/>
38+
* The user creates a {@link SpringDataEclipseStoreLazy} and puts a object in it.
39+
* This object is stored as with a default {@link BinaryTypeHandler}. But when it gets loaded,
40+
* it <b>does not</b> load as the stored object, but it gets wrapped in a {@link Lazy#Reference(Object)}.
41+
* </p>
42+
* <p>
43+
* Second case:<br/>
44+
* The actual lazy object gets loaded from the actual storage. In this case the {@link ObjectSwizzling} is
45+
* important! It's the actual {@link ObjectSwizzling} from the storage (not from the
46+
* {@link software.xdev.spring.data.eclipse.store.repository.support.copier.copier.EclipseSerializerRegisteringCopier}).
47+
* This means, the {@link SpringDataEclipseStoreLazy} holds the objectId of the original lazy in the original
48+
* storage.
49+
* Therefore if {@link SpringDataEclipseStoreLazy#get()} is called a new working copy of the lazy from the
50+
* storage is loaded.
51+
* </p>
3452
*/
3553
public final class SpringDataEclipseStoreLazyBinaryHandler
3654
extends AbstractBinaryHandlerCustom<SpringDataEclipseStoreLazy.Default<?>>
3755
{
3856
@SuppressWarnings("rawtypes")
39-
static final Constructor<SpringDataEclipseStoreLazy.Default> CONSTRUCTOR = XReflect.setAccessible(
57+
static final Constructor<SpringDataEclipseStoreLazy.Default> CONSTRUCTOR_SURROGATE_LAZY = XReflect.setAccessible(
4058
XReflect.getDeclaredConstructor(
4159
SpringDataEclipseStoreLazy.Default.class,
4260
long.class,
4361
ObjectSwizzling.class
4462
)
4563
);
4664

47-
private final ObjectSwizzling objectSwizzling;
65+
public static final int OFFSET_UNWRAPPED_OBJECT = 8;
66+
public static final int OFFSET_LAZY = 0;
4867

49-
public SpringDataEclipseStoreLazyBinaryHandler(final ObjectSwizzling objectSwizzling)
68+
private final ObjectSwizzling originalStoreLoader;
69+
70+
public SpringDataEclipseStoreLazyBinaryHandler(final ObjectSwizzling originalStoreLoader)
5071
{
5172
super(
5273
SpringDataEclipseStoreLazy.Default.genericType(),
5374
CustomFields(
54-
CustomField(Object.class, "subject")
75+
CustomField(Object.class, "lazySubject"),
76+
CustomField(Object.class, "unwrappedSubject")
5577
)
5678
);
57-
this.objectSwizzling = Objects.requireNonNull(objectSwizzling);
79+
this.originalStoreLoader = Objects.requireNonNull(originalStoreLoader);
5880
}
5981

6082
@Override
61-
public final void store(
83+
public void store(
6284
final Binary data,
6385
final SpringDataEclipseStoreLazy.Default<?> instance,
6486
final long objectId,
6587
final PersistenceStoreHandler<Binary> handler
6688
)
6789
{
68-
final long referenceOid = instance.objectId();
69-
data.storeEntityHeader(Binary.referenceBinaryLength(1), this.typeId(), objectId);
70-
data.store_long(referenceOid);
90+
data.storeEntityHeader(Binary.referenceBinaryLength(2), this.typeId(), objectId);
91+
if(instance.getObjectToBeWrapped() != null)
92+
{
93+
// Store unwrapped Object
94+
final long newObjectId = handler.applyEager(instance.getObjectToBeWrapped());
95+
data.store_long(OFFSET_UNWRAPPED_OBJECT, newObjectId);
96+
}
97+
else
98+
{
99+
// Store only reference to lazy
100+
data.store_long(OFFSET_LAZY, instance.objectId());
101+
}
71102
instance.setStored();
72103
}
73104

74105
@SuppressWarnings("unchecked")
75106
@Override
76-
public final SpringDataEclipseStoreLazy.Default<?> create(final Binary data, final PersistenceLoadHandler handler)
107+
public SpringDataEclipseStoreLazy.Default<?> create(final Binary data, final PersistenceLoadHandler handler)
77108
{
78-
final long objectId = data.read_long(0);
109+
final long objectIdOfLazy = data.read_long(OFFSET_LAZY);
110+
final long objectIdOfUnwrappedObject = data.read_long(OFFSET_UNWRAPPED_OBJECT);
79111

80-
return Lazy.register(
81-
XReflect.invoke(CONSTRUCTOR, objectId, this.objectSwizzling)
82-
);
112+
if(objectIdOfUnwrappedObject == 0)
113+
{
114+
return Lazy.register(
115+
XReflect.invoke(CONSTRUCTOR_SURROGATE_LAZY, objectIdOfLazy, this.originalStoreLoader)
116+
);
117+
}
118+
return XMemory.instantiateBlank(SpringDataEclipseStoreLazy.Default.class);
83119
}
84120

85121
@Override
86-
public final void updateState(
122+
public void updateState(
87123
final Binary data,
88124
final SpringDataEclipseStoreLazy.Default<?> instance,
89125
final PersistenceLoadHandler handler
90126
)
91127
{
92-
// no-op
128+
this.updateStateT(data, instance, handler);
129+
}
130+
131+
private <T> void updateStateT(
132+
final Binary data,
133+
final SpringDataEclipseStoreLazy.Default<T> instance,
134+
final PersistenceLoadHandler handler
135+
)
136+
{
137+
final long objectIdOfUnwrappedObject = data.read_long(OFFSET_UNWRAPPED_OBJECT);
138+
139+
if(objectIdOfUnwrappedObject != 0)
140+
{
141+
instance.setWrappedLazy(Lazy.Reference((T)handler.lookupObject(objectIdOfUnwrappedObject)));
142+
}
93143
}
94144

95145
@Override
@@ -122,10 +172,15 @@ public final boolean hasVaryingPersistedLengthInstances()
122172

123173
@Override
124174
public final void iterateLoadableReferences(
125-
final Binary offset,
175+
final Binary data,
126176
final PersistenceReferenceLoader iterator
127177
)
128178
{
129-
// the lazy reference is not naturally loadable, but special-handled by this handler
179+
final long objectIdOfUnwrappedObject = data.read_long(OFFSET_UNWRAPPED_OBJECT);
180+
181+
if(objectIdOfUnwrappedObject != 0)
182+
{
183+
iterator.acceptObjectId(objectIdOfUnwrappedObject);
184+
}
130185
}
131186
}

spring-data-eclipse-store/src/main/java/software/xdev/spring/data/eclipse/store/repository/support/copier/working/RecursiveWorkingCopier.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ private <E> SpringDataEclipseStoreLazy<E> createNewLazy(
330330
{
331331
// This lazy should never be used again!
332332
// It is though of as a temporary copy to merge back into the original-storage-data.
333-
return (SpringDataEclipseStoreLazy<E>)SpringDataEclipseStoreLazy.buildOnlyForStorage(oldLazy.objectId());
333+
return oldLazy.copy();
334334
}
335335
}
336336

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright © 2023 XDEV Software (https://xdev.software)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package software.xdev.spring.data.eclipse.store.integration.isolated.tests.lazy;
17+
18+
import java.util.List;
19+
20+
import org.eclipse.serializer.reference.Lazy;
21+
22+
23+
public class ComplexLazyObject
24+
{
25+
private Lazy<SimpleObject> simpleObject;
26+
private List<Lazy<List<String>>> listOfLazyListOfString;
27+
28+
public ComplexLazyObject(
29+
final Lazy<SimpleObject> simpleObject,
30+
final List<Lazy<List<String>>> listOfLazyListOfString)
31+
{
32+
this.simpleObject = simpleObject;
33+
this.listOfLazyListOfString = listOfLazyListOfString;
34+
}
35+
36+
public Lazy<SimpleObject> getSimpleObject()
37+
{
38+
return this.simpleObject;
39+
}
40+
41+
public void setSimpleObject(final Lazy<SimpleObject> simpleObject)
42+
{
43+
this.simpleObject = simpleObject;
44+
}
45+
46+
public List<Lazy<List<String>>> getListOfLazyListOfString()
47+
{
48+
return this.listOfLazyListOfString;
49+
}
50+
51+
public void setListOfLazyListOfString(final List<Lazy<List<String>>> listOfLazyListOfString)
52+
{
53+
this.listOfLazyListOfString = listOfLazyListOfString;
54+
}
55+
}

0 commit comments

Comments
 (0)