Skip to content

Commit 80c9fc6

Browse files
committed
moved withClone and withSelfCopy methods to CopyContext
1 parent 05ec6c0 commit 80c9fc6

File tree

4 files changed

+89
-20
lines changed

4 files changed

+89
-20
lines changed

src/main/java/org/xmlobjects/util/copy/AbstractCloner.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ final void setCopyBuilder(CopyBuilder builder) {
4040
@SuppressWarnings("unchecked")
4141
public final <E> E deepCopy(E value) {
4242
return value instanceof Copyable copyable ?
43-
(E) copyable.deepCopy(builder) :
43+
(E) copyable.deepCopy(builder, builder.getContext()) :
4444
builder.deepCopy(value);
4545
}
4646

src/main/java/org/xmlobjects/util/copy/CopyBuilder.java

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ public class CopyBuilder {
3535
private static final ThreadLocal<CopyContext> contexts = ThreadLocal.withInitial(CopyContext::new);
3636
private static final AbstractCloner<Object> IDENTITY_CLONER = new IdentityCloner();
3737
private static final AbstractCloner<Object> NULL_CLONER = new NullCloner();
38-
private static final Object NULL = new Object();
3938

4039
private final Map<Class<?>, AbstractCloner<?>> cloners = new ConcurrentHashMap<>();
4140
private final Set<Class<?>> immutables = ConcurrentHashMap.newKeySet();
@@ -46,11 +45,6 @@ public class CopyBuilder {
4645

4746
private volatile boolean failOnError;
4847

49-
private static class CopyContext {
50-
private final Map<Object, Object> clones = new IdentityHashMap<>();
51-
private boolean isCopying;
52-
}
53-
5448
public CopyBuilder() {
5549
registerKnownCloners();
5650
}
@@ -102,26 +96,27 @@ public CopyBuilder failOnError(boolean failOnError) {
10296
return this;
10397
}
10498

99+
CopyContext getContext() {
100+
return contexts.get();
101+
}
102+
105103
@SuppressWarnings("unchecked")
106104
private <T> T copy(T src, T dest, Class<T> template, boolean shallowCopy) {
107105
if (src == null || src == dest) {
108106
return dest;
109107
}
110108

111109
CopyContext context = contexts.get();
112-
boolean isInitial = !context.isCopying;
113-
if (isInitial) {
114-
context.isCopying = true;
115-
}
110+
boolean isInitial = context.isInitial();
116111

117-
T clone = (T) context.clones.get(src);
112+
T clone = (T) context.getClone(src);
118113
try {
119114
if (clone == null) {
120115
if (shallowCopy
121116
&& isInitial
122117
&& dest == null
123118
&& src instanceof Copyable copyable) {
124-
clone = (T) copyable.shallowCopy(this);
119+
clone = (T) copyable.shallowCopy(this, context);
125120
} else {
126121
if (template == null) {
127122
template = (Class<T>) src.getClass();
@@ -131,7 +126,7 @@ private <T> T copy(T src, T dest, Class<T> template, boolean shallowCopy) {
131126
if (src instanceof Child child) {
132127
Child parent = child.getParent();
133128
if (parent != null) {
134-
context.clones.putIfAbsent(parent, parent);
129+
context.addCloneIfAbsent(parent, parent);
135130
}
136131
}
137132

@@ -141,12 +136,12 @@ private <T> T copy(T src, T dest, Class<T> template, boolean shallowCopy) {
141136
dest = cloner.newInstance(src, shallowCopy);
142137
}
143138

144-
context.clones.put(src, dest != null ? dest : NULL);
139+
context.addClone(src, dest);
145140
}
146141

147142
clone = cloner.copy(src, dest, shallowCopy);
148143
}
149-
} else if (clone == NULL) {
144+
} else if (context.isNullClone(clone)) {
150145
clone = null;
151146
}
152147
} catch (Throwable e) {
@@ -157,8 +152,7 @@ private <T> T copy(T src, T dest, Class<T> template, boolean shallowCopy) {
157152
}
158153
} finally {
159154
if (isInitial) {
160-
context.isCopying = false;
161-
context.clones.clear();
155+
context.clear();
162156
contexts.remove();
163157

164158
// unset parent on initial source object
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* citygml4j - The Open Source Java API for CityGML
3+
* https://github.com/citygml4j
4+
*
5+
* Copyright 2013-2025 Claus Nagel <claus.nagel@gmail.com>
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
package org.xmlobjects.util.copy;
21+
22+
import java.util.IdentityHashMap;
23+
import java.util.Map;
24+
import java.util.concurrent.atomic.AtomicBoolean;
25+
import java.util.function.Supplier;
26+
27+
public class CopyContext {
28+
private static final Object NULL_CLONE = new Object();
29+
private final Map<Object, Object> clones = new IdentityHashMap<>();
30+
private final AtomicBoolean initial = new AtomicBoolean(true);
31+
32+
CopyContext() {
33+
}
34+
35+
boolean isInitial() {
36+
return initial.getAndSet(false);
37+
}
38+
39+
Object getClone(Object src) {
40+
return clones.get(src);
41+
}
42+
43+
void addClone(Object src, Object dest) {
44+
clones.put(src, dest != null ? dest : NULL_CLONE);
45+
}
46+
47+
void addCloneIfAbsent(Object src, Object dest) {
48+
clones.putIfAbsent(src, dest != null ? dest : NULL_CLONE);
49+
}
50+
51+
boolean isNullClone(Object src) {
52+
return src == null || src == NULL_CLONE;
53+
}
54+
55+
public <T> CopyContext withClone(T src, Supplier<T> supplier) {
56+
if (src != null) {
57+
addClone(src, supplier.get());
58+
}
59+
60+
return this;
61+
}
62+
63+
public CopyContext withSelfCopy(Object src) {
64+
if (src != null) {
65+
addClone(src, src);
66+
}
67+
68+
return this;
69+
}
70+
71+
void clear() {
72+
clones.clear();
73+
initial.set(true);
74+
}
75+
}

src/main/java/org/xmlobjects/util/copy/Copyable.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
package org.xmlobjects.util.copy;
2121

2222
public interface Copyable {
23-
default Copyable shallowCopy(CopyBuilder builder) {
23+
default Copyable shallowCopy(CopyBuilder builder, CopyContext context) {
2424
return builder.shallowCopy(this);
2525
}
2626

27-
default Copyable deepCopy(CopyBuilder builder) {
27+
default Copyable deepCopy(CopyBuilder builder, CopyContext context) {
2828
return builder.deepCopy(this);
2929
}
3030
}

0 commit comments

Comments
 (0)