15
15
*/
16
16
package org .springframework .data .couchbase .core ;
17
17
18
+ import java .lang .reflect .InaccessibleObjectException ;
19
+ import java .util .Map ;
20
+ import java .util .Set ;
21
+
18
22
import org .slf4j .Logger ;
19
23
import org .slf4j .LoggerFactory ;
20
24
import org .springframework .context .ApplicationContext ;
26
30
import org .springframework .data .couchbase .core .mapping .CouchbasePersistentProperty ;
27
31
import org .springframework .data .couchbase .core .mapping .event .AfterSaveEvent ;
28
32
import org .springframework .data .couchbase .core .mapping .event .CouchbaseMappingEvent ;
33
+ import org .springframework .data .couchbase .core .support .TemplateUtils ;
29
34
import org .springframework .data .couchbase .repository .support .MappingCouchbaseEntityInformation ;
30
35
import org .springframework .data .couchbase .repository .support .TransactionResultHolder ;
31
36
import org .springframework .data .couchbase .transaction .CouchbaseResourceHolder ;
32
37
import org .springframework .data .mapping .PersistentPropertyAccessor ;
33
38
import org .springframework .data .mapping .context .MappingContext ;
34
39
import org .springframework .data .mapping .model .ConvertingPropertyAccessor ;
35
-
36
40
import org .springframework .util .ClassUtils ;
37
41
38
- import java .util .Map ;
39
- import java .util .Set ;
42
+ import com .couchbase .client .core .error .CouchbaseException ;
40
43
41
44
public abstract class AbstractTemplateSupport {
42
45
@@ -47,7 +50,8 @@ public abstract class AbstractTemplateSupport {
47
50
ApplicationContext applicationContext ;
48
51
static final Logger LOG = LoggerFactory .getLogger (AbstractTemplateSupport .class );
49
52
50
- public AbstractTemplateSupport (ReactiveCouchbaseTemplate template , CouchbaseConverter converter , TranslationService translationService ) {
53
+ public AbstractTemplateSupport (ReactiveCouchbaseTemplate template , CouchbaseConverter converter ,
54
+ TranslationService translationService ) {
51
55
this .template = template ;
52
56
this .converter = converter ;
53
57
this .mappingContext = converter .getMappingContext ();
@@ -56,10 +60,8 @@ public AbstractTemplateSupport(ReactiveCouchbaseTemplate template, CouchbaseConv
56
60
57
61
abstract ReactiveCouchbaseTemplate getReactiveTemplate ();
58
62
59
- public <T > T decodeEntityBase (String id , String source , long cas , Class <T > entityClass , String scope , String collection ,
60
- TransactionResultHolder txResultHolder , CouchbaseResourceHolder holder ) {
61
- final CouchbaseDocument converted = new CouchbaseDocument (id );
62
- converted .setId (id );
63
+ public <T > T decodeEntityBase (String id , String source , Long cas , Class <T > entityClass , String scope ,
64
+ String collection , TransactionResultHolder txResultHolder , CouchbaseResourceHolder holder ) {
63
65
64
66
// this is the entity class defined for the repository. It may not be the class of the document that was read
65
67
// we will reset it after reading the document
@@ -79,18 +81,32 @@ public <T> T decodeEntityBase(String id, String source, long cas, Class<T> entit
79
81
// to unwrap. This results in List<String[]> being unwrapped past String[] to String, so this may also be a
80
82
// Collection (or Array) of entityClass. We have no way of knowing - so just assume it is what we are told.
81
83
// if this is a Collection or array, only the first element will be returned.
84
+ final CouchbaseDocument converted = new CouchbaseDocument (id );
82
85
Set <Map .Entry <String , Object >> set = ((CouchbaseDocument ) translationService .decode (source , converted ))
83
86
.getContent ().entrySet ();
84
87
return (T ) set .iterator ().next ().getValue ();
85
88
}
86
89
90
+ if (id == null ) {
91
+ throw new CouchbaseException (TemplateUtils .SELECT_ID + " was null. Either use #{#n1ql.selectEntity} or project "
92
+ + TemplateUtils .SELECT_ID );
93
+ }
94
+
95
+ final CouchbaseDocument converted = new CouchbaseDocument (id );
96
+
87
97
// if possible, set the version property in the source so that if the constructor has a long version argument,
88
- // it will have a value an not fail (as null is not a valid argument for a long argument). This possible failure
98
+ // it will have a value and not fail (as null is not a valid argument for a long argument). This possible failure
89
99
// can be avoid by defining the argument as Long instead of long.
90
100
// persistentEntity is still the (possibly abstract) class specified in the repository definition
91
101
// it's possible that the abstract class does not have a version property, and this won't be able to set the version
92
- if (cas != 0 && persistentEntity .getVersionProperty () != null ) {
93
- converted .put (persistentEntity .getVersionProperty ().getName (), cas );
102
+ if (persistentEntity .getVersionProperty () != null ) {
103
+ if (cas == null ) {
104
+ throw new CouchbaseException ("version/cas in the entity but " + TemplateUtils .SELECT_CAS
105
+ + " was not in result. Either use #{#n1ql.selectEntity} or project " + TemplateUtils .SELECT_CAS );
106
+ }
107
+ if (cas != 0 ) {
108
+ converted .put (persistentEntity .getVersionProperty ().getName (), cas );
109
+ }
94
110
}
95
111
96
112
// if the constructor has an argument that is long version, then construction will fail if the 'version'
@@ -101,13 +117,13 @@ public <T> T decodeEntityBase(String id, String source, long cas, Class<T> entit
101
117
102
118
persistentEntity = couldBePersistentEntity (readEntity .getClass ());
103
119
104
- if (cas != 0 && persistentEntity .getVersionProperty () != null ) {
120
+ if (cas != null && cas != 0 && persistentEntity .getVersionProperty () != null ) {
105
121
accessor .setProperty (persistentEntity .getVersionProperty (), cas );
106
122
}
107
123
N1qlJoinResolver .handleProperties (persistentEntity , accessor , getReactiveTemplate (), id , scope , collection );
108
124
109
- if (holder != null ){
110
- holder .transactionResultHolder (txResultHolder , (T )accessor .getBean ());
125
+ if (holder != null ) {
126
+ holder .transactionResultHolder (txResultHolder , (T ) accessor .getBean ());
111
127
}
112
128
113
129
return accessor .getBean ();
@@ -117,13 +133,16 @@ CouchbasePersistentEntity couldBePersistentEntity(Class<?> entityClass) {
117
133
if (ClassUtils .isPrimitiveOrWrapper (entityClass ) || entityClass == String .class ) {
118
134
return null ;
119
135
}
120
- return mappingContext . getPersistentEntity ( entityClass );
121
- }
122
-
136
+ try {
137
+ return mappingContext . getPersistentEntity ( entityClass );
138
+ } catch ( InaccessibleObjectException t ) {
123
139
140
+ }
141
+ return null ;
142
+ }
124
143
125
144
public <T > T applyResultBase (T entity , CouchbaseDocument converted , Object id , long cas ,
126
- TransactionResultHolder txResultHolder , CouchbaseResourceHolder holder ) {
145
+ TransactionResultHolder txResultHolder , CouchbaseResourceHolder holder ) {
127
146
ConvertingPropertyAccessor <Object > accessor = getPropertyAccessor (entity );
128
147
129
148
final CouchbasePersistentEntity <?> persistentEntity = converter .getMappingContext ()
@@ -139,8 +158,8 @@ public <T> T applyResultBase(T entity, CouchbaseDocument converted, Object id, l
139
158
accessor .setProperty (versionProperty , cas );
140
159
}
141
160
142
- if (holder != null ){
143
- holder .transactionResultHolder (txResultHolder , (T )accessor .getBean ());
161
+ if (holder != null ) {
162
+ holder .transactionResultHolder (txResultHolder , (T ) accessor .getBean ());
144
163
}
145
164
maybeEmitEvent (new AfterSaveEvent (accessor .getBean (), converted ));
146
165
return (T ) accessor .getBean ();
@@ -202,7 +221,7 @@ private boolean canPublishEvent() {
202
221
return this .applicationContext != null ;
203
222
}
204
223
205
- public TranslationService getTranslationService (){
224
+ public TranslationService getTranslationService () {
206
225
return translationService ;
207
226
}
208
227
}
0 commit comments