1
|
/**
|
2
|
* Copyright (C) 2007 EDIT
|
3
|
* European Distributed Institute of Taxonomy
|
4
|
* http://www.e-taxonomy.eu
|
5
|
*
|
6
|
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
7
|
* See LICENSE.TXT at the top of this package for the full license terms.
|
8
|
*/
|
9
|
|
10
|
package eu.etaxonomy.cdm.model.term;
|
11
|
|
12
|
import java.lang.reflect.Constructor;
|
13
|
import java.util.HashSet;
|
14
|
import java.util.List;
|
15
|
import java.util.Map;
|
16
|
import java.util.Set;
|
17
|
import java.util.UUID;
|
18
|
|
19
|
import javax.persistence.Column;
|
20
|
import javax.persistence.Entity;
|
21
|
import javax.persistence.FetchType;
|
22
|
import javax.persistence.Inheritance;
|
23
|
import javax.persistence.InheritanceType;
|
24
|
import javax.persistence.ManyToMany;
|
25
|
import javax.persistence.ManyToOne;
|
26
|
import javax.persistence.OneToMany;
|
27
|
import javax.persistence.Transient;
|
28
|
import javax.xml.bind.annotation.XmlAccessType;
|
29
|
import javax.xml.bind.annotation.XmlAccessorType;
|
30
|
import javax.xml.bind.annotation.XmlElement;
|
31
|
import javax.xml.bind.annotation.XmlElementWrapper;
|
32
|
import javax.xml.bind.annotation.XmlIDREF;
|
33
|
import javax.xml.bind.annotation.XmlRootElement;
|
34
|
import javax.xml.bind.annotation.XmlSchemaType;
|
35
|
import javax.xml.bind.annotation.XmlSeeAlso;
|
36
|
import javax.xml.bind.annotation.XmlTransient;
|
37
|
import javax.xml.bind.annotation.XmlType;
|
38
|
|
39
|
import org.apache.logging.log4j.LogManager;
|
40
|
import org.apache.logging.log4j.Logger;
|
41
|
import org.hibernate.annotations.Cascade;
|
42
|
import org.hibernate.annotations.CascadeType;
|
43
|
import org.hibernate.envers.Audited;
|
44
|
import org.hibernate.proxy.HibernateProxy;
|
45
|
import org.hibernate.proxy.LazyInitializer;
|
46
|
import org.hibernate.search.annotations.ClassBridge;
|
47
|
|
48
|
import au.com.bytecode.opencsv.CSVWriter;
|
49
|
import eu.etaxonomy.cdm.common.CdmUtils;
|
50
|
import eu.etaxonomy.cdm.common.URI;
|
51
|
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
|
52
|
import eu.etaxonomy.cdm.hibernate.search.DefinedTermBaseClassBridge;
|
53
|
import eu.etaxonomy.cdm.model.ICdmUuidCacher;
|
54
|
import eu.etaxonomy.cdm.model.common.AnnotationType;
|
55
|
import eu.etaxonomy.cdm.model.common.ExtensionType;
|
56
|
import eu.etaxonomy.cdm.model.common.ExternallyManaged;
|
57
|
import eu.etaxonomy.cdm.model.common.Language;
|
58
|
import eu.etaxonomy.cdm.model.common.MarkerType;
|
59
|
import eu.etaxonomy.cdm.model.description.Feature;
|
60
|
import eu.etaxonomy.cdm.model.description.MeasurementUnit;
|
61
|
import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
|
62
|
import eu.etaxonomy.cdm.model.description.TextFormat;
|
63
|
import eu.etaxonomy.cdm.model.location.NamedAreaType;
|
64
|
import eu.etaxonomy.cdm.model.location.ReferenceSystem;
|
65
|
import eu.etaxonomy.cdm.model.media.Media;
|
66
|
import eu.etaxonomy.cdm.model.media.RightsType;
|
67
|
import eu.etaxonomy.cdm.model.name.NomenclaturalCode;
|
68
|
import eu.etaxonomy.cdm.model.occurrence.DerivationEventType;
|
69
|
import eu.etaxonomy.cdm.model.occurrence.PreservationMethod;
|
70
|
|
71
|
|
72
|
/**
|
73
|
* workaround for enumerations, base type according to TDWG. For linear ordering
|
74
|
* use partOf relation and BreadthFirst. Default iterator order should therefore
|
75
|
* be BreadthFirst (not DepthFirst)
|
76
|
* @author m.doering
|
77
|
* @since 08-Nov-2007 13:06:19
|
78
|
*/
|
79
|
@XmlAccessorType(XmlAccessType.FIELD)
|
80
|
@XmlType(name = "DefinedTermBase", propOrder = {
|
81
|
"media",
|
82
|
"vocabulary",
|
83
|
"idInVocabulary",
|
84
|
"symbol",
|
85
|
"symbol2",
|
86
|
"externallyManaged",
|
87
|
})
|
88
|
@XmlRootElement(name = "DefinedTermBase")
|
89
|
@XmlSeeAlso({
|
90
|
AnnotationType.class,
|
91
|
DerivationEventType.class,
|
92
|
DefinedTerm.class,
|
93
|
ExtensionType.class,
|
94
|
Feature.class,
|
95
|
Language.class,
|
96
|
MarkerType.class,
|
97
|
MeasurementUnit.class,
|
98
|
NamedAreaType.class,
|
99
|
NomenclaturalCode.class,
|
100
|
PreservationMethod.class,
|
101
|
ReferenceSystem.class,
|
102
|
RightsType.class,
|
103
|
StatisticalMeasure.class,
|
104
|
TextFormat.class
|
105
|
})
|
106
|
@Entity
|
107
|
@Audited
|
108
|
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
|
109
|
@ClassBridge(impl=DefinedTermBaseClassBridge.class)
|
110
|
//TODO Comparable implemented only for fixing failing JAXB import, may be removed when this is fixed
|
111
|
public abstract class DefinedTermBase<T extends DefinedTermBase>
|
112
|
extends TermBase
|
113
|
implements IDefinedTerm<T>, Comparable<T> {
|
114
|
|
115
|
private static final long serialVersionUID = 2931811562248571531L;
|
116
|
private static final Logger logger = LogManager.getLogger(DefinedTermBase.class);
|
117
|
|
118
|
// @XmlElement(name = "KindOf")
|
119
|
// @XmlIDREF
|
120
|
// @XmlSchemaType(name = "IDREF")
|
121
|
@XmlTransient
|
122
|
@ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
|
123
|
@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
|
124
|
private T kindOf;
|
125
|
|
126
|
/**
|
127
|
* FIXME - Hibernate returns this as a collection of CGLibProxy$$DefinedTermBase objects
|
128
|
* which can't be cast to instances of T - can we explicitly initialize these terms using
|
129
|
* Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
|
130
|
*/
|
131
|
// @XmlElementWrapper(name = "Generalizations")
|
132
|
// @XmlElement(name = "GeneralizationOf")
|
133
|
// @XmlIDREF
|
134
|
// @XmlSchemaType(name = "IDREF")
|
135
|
@XmlTransient
|
136
|
@OneToMany(fetch=FetchType.LAZY, mappedBy = "kindOf", targetEntity = DefinedTermBase.class)
|
137
|
@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
|
138
|
private Set<T> generalizationOf = new HashSet<>();
|
139
|
|
140
|
// @XmlElement(name = "PartOf")
|
141
|
// @XmlIDREF
|
142
|
// @XmlSchemaType(name = "IDREF")
|
143
|
@XmlTransient
|
144
|
@ManyToOne(fetch = FetchType.LAZY, targetEntity = DefinedTermBase.class)
|
145
|
@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
|
146
|
protected T partOf;
|
147
|
|
148
|
/**
|
149
|
* FIXME - Hibernate retuns this as a collection of CGLibProxy$$DefinedTermBase objects
|
150
|
* which can't be cast to instances of T - can we explicitly initialize these terms using
|
151
|
* Hibernate.initialize(), does this imply a distinct load, and find methods in the dao?
|
152
|
*/
|
153
|
// @XmlElementWrapper(name = "Includes")
|
154
|
// @XmlElement(name = "Include")
|
155
|
// @XmlIDREF
|
156
|
// @XmlSchemaType(name = "IDREF")
|
157
|
@XmlTransient
|
158
|
@OneToMany(fetch=FetchType.LAZY, mappedBy = "partOf", targetEntity = DefinedTermBase.class)
|
159
|
@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
|
160
|
private Set<T> includes = new HashSet<>();
|
161
|
|
162
|
@XmlElementWrapper(name = "Media")
|
163
|
@XmlElement(name = "Medium")
|
164
|
@XmlIDREF
|
165
|
@XmlSchemaType(name = "IDREF")
|
166
|
@ManyToMany(fetch = FetchType.LAZY)
|
167
|
@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
|
168
|
private Set<Media> media = new HashSet<>();
|
169
|
|
170
|
@XmlElement(name = "TermVocabulary")
|
171
|
@XmlIDREF
|
172
|
@XmlSchemaType(name = "IDREF")
|
173
|
@ManyToOne(fetch=FetchType.LAZY)
|
174
|
// @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE}) remove cascading #5754
|
175
|
protected TermVocabulary<T> vocabulary;
|
176
|
|
177
|
//the unique identifier/name this term uses in its given vocabulary #3479
|
178
|
@XmlElement(name = "idInVocabulary")
|
179
|
@Column(length=255)
|
180
|
//TODO Val #3379, #4245
|
181
|
// @NullOrNotEmpty
|
182
|
private String idInVocabulary; //the unique identifier/name this term uses in its given vocabulary #3479
|
183
|
|
184
|
@XmlElement(name = "symbol")
|
185
|
@Column(length=30)
|
186
|
//the symbol to be used in String representations for this term #5734
|
187
|
//this term can be changed by the database instance even if the term is not managed by this instance as it is only for representation and has no semantic or identifying character
|
188
|
//empty string is explicitly allowed and should be distinguished from NULL!
|
189
|
private String symbol;
|
190
|
|
191
|
@XmlElement(name = "symbol2")
|
192
|
@Column(length=30)
|
193
|
//the second symbol to be used in String representations for this term #7096
|
194
|
//this term can be changed by the database instance even if the term is not managed by this instance as it is only for representation and has no semantic or identifying character
|
195
|
//empty string is explicitly allowed and should be distinguished from NULL!
|
196
|
private String symbol2;
|
197
|
|
198
|
private ExternallyManaged externallyManaged;
|
199
|
|
200
|
//***************************** CONSTRUCTOR *******************************************/
|
201
|
|
202
|
//for hibernate use only, *packet* private required by bytebuddy
|
203
|
//2022-06-17: currently still needed protected as TaxEditor.TaxonRelationshipTypeInverseContainer inherits from DefinedTermBase
|
204
|
@Deprecated
|
205
|
protected DefinedTermBase(){}
|
206
|
|
207
|
protected DefinedTermBase(TermType type) {
|
208
|
super(type);
|
209
|
}
|
210
|
|
211
|
public DefinedTermBase(TermType type, String description, String label, String labelAbbrev, Language lang) {
|
212
|
super(type, description, label, labelAbbrev, lang);
|
213
|
}
|
214
|
public DefinedTermBase(TermType type, String description, String label, String labelAbbrev) {
|
215
|
super(type, description, label, labelAbbrev, null);
|
216
|
}
|
217
|
|
218
|
//********************** GETTER /SETTER *************************************
|
219
|
|
220
|
@Override
|
221
|
public String getIdInVocabulary() {
|
222
|
return idInVocabulary;
|
223
|
}
|
224
|
|
225
|
@Override
|
226
|
public void setIdInVocabulary(String idInVocabulary) {
|
227
|
this.idInVocabulary = CdmUtils.isBlank(idInVocabulary)? null : idInVocabulary;
|
228
|
}
|
229
|
|
230
|
@Override
|
231
|
public T getKindOf(){
|
232
|
if (this instanceof HibernateProxy) {
|
233
|
HibernateProxy proxy = (HibernateProxy) this;
|
234
|
LazyInitializer li = proxy.getHibernateLazyInitializer();
|
235
|
return (T)((T)li.getImplementation()).getKindOf();
|
236
|
} else {
|
237
|
return (T)DefinedTermBase.deproxy(this.kindOf, this.getClass());
|
238
|
}
|
239
|
}
|
240
|
|
241
|
public void setKindOf(T kindOf){
|
242
|
this.kindOf = kindOf;
|
243
|
}
|
244
|
|
245
|
@Override
|
246
|
public Set<T> getGeneralizationOf(){
|
247
|
return this.generalizationOf;
|
248
|
}
|
249
|
protected void setGeneralizationOf(Set<T> value) {
|
250
|
this.generalizationOf = value;
|
251
|
}
|
252
|
public void addGeneralizationOf(T generalization) {
|
253
|
checkTermType(generalization);
|
254
|
generalization.setKindOf(this);
|
255
|
this.generalizationOf.add(generalization);
|
256
|
}
|
257
|
public void removeGeneralization(T generalization) {
|
258
|
if(generalizationOf.contains(generalization)){
|
259
|
generalization.setKindOf(null);
|
260
|
this.generalizationOf.remove(generalization);
|
261
|
}
|
262
|
}
|
263
|
|
264
|
@Override
|
265
|
public T getPartOf(){
|
266
|
if (this instanceof HibernateProxy) {
|
267
|
HibernateProxy proxy = (HibernateProxy) this;
|
268
|
LazyInitializer li = proxy.getHibernateLazyInitializer();
|
269
|
return (T)((T)li.getImplementation()).getPartOf();
|
270
|
} else {
|
271
|
return (T)DefinedTermBase.deproxy(this.partOf, this.getClass());
|
272
|
}
|
273
|
}
|
274
|
|
275
|
/**
|
276
|
* @see #getPartOf()
|
277
|
*/
|
278
|
public void setPartOf(T partOf){
|
279
|
this.partOf = partOf;
|
280
|
}
|
281
|
|
282
|
|
283
|
//TODO Comparable implemented only for fixing failing JAXB imports, may be removed when this is fixed
|
284
|
@Override
|
285
|
@Deprecated //for inner use only
|
286
|
public int compareTo(T other) {
|
287
|
return ((Integer)this.getId()).compareTo(other.getId());
|
288
|
}
|
289
|
|
290
|
@Override
|
291
|
public Set<T> getIncludes(){
|
292
|
return this.includes;
|
293
|
}
|
294
|
|
295
|
/**
|
296
|
* @see #getIncludes()
|
297
|
*/
|
298
|
protected void setIncludes(Set<T> includes) {
|
299
|
this.includes = includes;
|
300
|
}
|
301
|
|
302
|
/**
|
303
|
* @see #getIncludes()
|
304
|
*/
|
305
|
public void addIncludes(T includes) {
|
306
|
checkTermType(includes);
|
307
|
includes.setPartOf(this);
|
308
|
this.includes.add(includes);
|
309
|
}
|
310
|
|
311
|
/**
|
312
|
* @see #getIncludes()
|
313
|
*/
|
314
|
public void removeIncludes(T includes) {
|
315
|
if(this.includes.contains(includes)) {
|
316
|
includes.setPartOf(null);
|
317
|
this.includes.remove(includes);
|
318
|
}
|
319
|
}
|
320
|
|
321
|
@Override
|
322
|
public Set<Media> getMedia(){
|
323
|
return this.media;
|
324
|
}
|
325
|
|
326
|
public void addMedia(Media media) {
|
327
|
this.media.add(media);
|
328
|
}
|
329
|
public void removeMedia(Media media) {
|
330
|
this.media.remove(media);
|
331
|
}
|
332
|
|
333
|
public TermVocabulary<T> getVocabulary() {
|
334
|
return this.vocabulary;
|
335
|
}
|
336
|
|
337
|
//for bedirectional use only, use vocabulary.addTerm instead
|
338
|
protected void setVocabulary(TermVocabulary<T> newVocabulary) {
|
339
|
this.vocabulary = newVocabulary;
|
340
|
}
|
341
|
|
342
|
public String getSymbol() {
|
343
|
return symbol;
|
344
|
}
|
345
|
public void setSymbol(String symbol) {
|
346
|
this.symbol = symbol;
|
347
|
}
|
348
|
|
349
|
public String getSymbol2() {
|
350
|
return symbol2;
|
351
|
}
|
352
|
public void setSymbol2(String symbol2) {
|
353
|
this.symbol2 = symbol2;
|
354
|
}
|
355
|
|
356
|
//******************************* METHODS ******************************************************/
|
357
|
|
358
|
@Override
|
359
|
public boolean isKindOf(T ancestor) {
|
360
|
if (kindOf == null || ancestor == null){
|
361
|
return false;
|
362
|
}else if (kindOf.equals(ancestor)){
|
363
|
return true;
|
364
|
}else{
|
365
|
return kindOf.isKindOf(ancestor);
|
366
|
}
|
367
|
}
|
368
|
|
369
|
@Override
|
370
|
public Set<T> getGeneralizationOf(boolean recursive) {
|
371
|
Set<T> result = new HashSet<T>();
|
372
|
result.addAll(this.generalizationOf);
|
373
|
if (recursive){
|
374
|
for (T child : this.generalizationOf){
|
375
|
result.addAll(child.getGeneralizationOf());
|
376
|
}
|
377
|
}
|
378
|
return result;
|
379
|
}
|
380
|
|
381
|
public abstract void resetTerms();
|
382
|
|
383
|
protected abstract void setDefaultTerms(TermVocabulary<T> termVocabulary);
|
384
|
|
385
|
@Override
|
386
|
public T readCsvLine(Class<T> termClass, List<String> csvLine, TermType termType, Map<UUID,DefinedTermBase> terms, boolean abbrevAsId) {
|
387
|
try {
|
388
|
T newInstance = getInstance(termClass, termType);
|
389
|
readCsvLine(newInstance, csvLine, Language.CSV_LANGUAGE(), abbrevAsId);
|
390
|
readIsPartOf(newInstance, csvLine, terms);
|
391
|
return newInstance;
|
392
|
} catch (Exception e) {
|
393
|
logger.error(e);
|
394
|
for(StackTraceElement ste : e.getStackTrace()) {
|
395
|
logger.error(ste);
|
396
|
}
|
397
|
throw new RuntimeException(e);
|
398
|
}
|
399
|
}
|
400
|
|
401
|
protected static <TERM extends DefinedTermBase> TERM readCsvLine(TERM newInstance, List<String> csvLine, Language lang, boolean abbrevAsId) {
|
402
|
newInstance.setUuid(UUID.fromString(csvLine.get(0)));
|
403
|
String uriStr = CdmUtils.Ne(csvLine.get(1));
|
404
|
newInstance.setUri(uriStr == null? null: URI.create(uriStr));
|
405
|
String label = csvLine.get(2).trim();
|
406
|
String description = CdmUtils.Ne(csvLine.get(3).trim());
|
407
|
String abbreviatedLabel = CdmUtils.Ne(csvLine.get(4).trim());
|
408
|
if (CdmUtils.isBlank(abbreviatedLabel)){
|
409
|
abbreviatedLabel = null;
|
410
|
}
|
411
|
if (abbrevAsId){
|
412
|
newInstance.setIdInVocabulary(abbreviatedLabel); //new in 3.3
|
413
|
}
|
414
|
newInstance.addRepresentation(Representation.NewInstance(description, label, abbreviatedLabel, lang) );
|
415
|
|
416
|
return newInstance;
|
417
|
}
|
418
|
|
419
|
protected void readIsPartOf(T newInstance, List<String> csvLine, Map<UUID, DefinedTermBase> terms){
|
420
|
int index = partOfCsvLineIndex();
|
421
|
if (index != -1){
|
422
|
String partOfString = csvLine.get(index);
|
423
|
if(CdmUtils.isNotBlank(partOfString)) {
|
424
|
UUID partOfUuid = UUID.fromString(partOfString);
|
425
|
DefinedTermBase partOf = terms.get(partOfUuid);
|
426
|
partOf.addIncludes(newInstance);
|
427
|
}
|
428
|
}
|
429
|
}
|
430
|
|
431
|
protected int partOfCsvLineIndex() {
|
432
|
return -1;
|
433
|
}
|
434
|
|
435
|
private <T extends DefinedTermBase> T getInstance(Class<? extends DefinedTermBase> termClass, TermType termType) {
|
436
|
try {
|
437
|
Constructor<T> c = ((Class<T>)termClass).getDeclaredConstructor();
|
438
|
c.setAccessible(true);
|
439
|
T termInstance = c.newInstance();
|
440
|
termInstance.setTermType(termType);
|
441
|
return termInstance;
|
442
|
} catch (Exception e) {
|
443
|
throw new RuntimeException(e);
|
444
|
}
|
445
|
}
|
446
|
|
447
|
@Override
|
448
|
public void writeCsvLine(CSVWriter writer, T term) {
|
449
|
String [] line = new String[4];
|
450
|
line[0] = term.getUuid().toString();
|
451
|
line[1] = term.getUri().toString();
|
452
|
line[2] = term.getLabel();
|
453
|
line[3] = term.getDescription();
|
454
|
writer.writeNext(line);
|
455
|
}
|
456
|
|
457
|
@Transient
|
458
|
public T getByUuid(UUID uuid){
|
459
|
return this.vocabulary.findTermByUuid(uuid);
|
460
|
}
|
461
|
|
462
|
/**
|
463
|
* Throws {@link IllegalArgumentException} if the given
|
464
|
* term has not the same term type as this term or if term type is null.
|
465
|
* @param term
|
466
|
*/
|
467
|
private void checkTermType(IHasTermType term) {
|
468
|
IHasTermType.checkTermTypes(term, this);
|
469
|
}
|
470
|
|
471
|
|
472
|
//*********************** CLONE ********************************************************/
|
473
|
|
474
|
/**
|
475
|
* Clones <i>this</i> DefinedTermBase. This is a shortcut that enables to create
|
476
|
* a new instance that differs only slightly from <i>this</i> defined term base by
|
477
|
* modifying only some of the attributes.
|
478
|
*
|
479
|
* @see eu.etaxonomy.cdm.model.term.TermBase#clone()
|
480
|
* @see java.lang.Object#clone()
|
481
|
*/
|
482
|
@Override
|
483
|
public DefinedTermBase<T> clone() {
|
484
|
try {
|
485
|
DefinedTermBase<T> result = (DefinedTermBase<T>) super.clone();
|
486
|
|
487
|
result.generalizationOf = new HashSet<>();
|
488
|
for (DefinedTermBase<T> generalizationOf : this.generalizationOf){
|
489
|
result.generalizationOf.add((T)generalizationOf.clone());
|
490
|
}
|
491
|
|
492
|
result.includes = new HashSet<>();
|
493
|
|
494
|
for (DefinedTermBase<?> include: this.includes){
|
495
|
result.includes.add((T)include.clone());
|
496
|
}
|
497
|
|
498
|
result.media = new HashSet<>();
|
499
|
|
500
|
for (Media media: this.media){
|
501
|
result.addMedia(media);
|
502
|
}
|
503
|
|
504
|
return result;
|
505
|
}catch (CloneNotSupportedException e) {
|
506
|
logger.warn("Object does not implement cloneable");
|
507
|
e.printStackTrace();
|
508
|
return null;
|
509
|
}
|
510
|
}
|
511
|
|
512
|
// Currently the CDM Caching mechanism is only used for caching terms
|
513
|
private static ICdmUuidCacher cacher;
|
514
|
|
515
|
|
516
|
/**
|
517
|
* Gets the CDM cacher object
|
518
|
*
|
519
|
* @return the CDM cacher object
|
520
|
*/
|
521
|
public static ICdmUuidCacher getCacher() {
|
522
|
return cacher;
|
523
|
}
|
524
|
|
525
|
/**
|
526
|
* Sets the CDM cacher object
|
527
|
*
|
528
|
* @param cacher the CDM cacher object
|
529
|
*/
|
530
|
public static void setCacher(ICdmUuidCacher cacher) {
|
531
|
DefinedTermBase.cacher = cacher;
|
532
|
}
|
533
|
|
534
|
public static <T extends DefinedTermBase> T getTermByClassAndUUID(Class<T> clazz, UUID uuid) {
|
535
|
if(cacher != null) {
|
536
|
Object obj = HibernateProxyHelper.deproxy(getCacher().load(uuid));
|
537
|
|
538
|
if(obj != null && obj.getClass().equals(clazz)) {
|
539
|
return (T)obj;
|
540
|
}
|
541
|
}
|
542
|
return null;
|
543
|
}
|
544
|
}
|