1515 */
1616package org .springframework .data .couchbase .core ;
1717
18+ import java .lang .reflect .InaccessibleObjectException ;
19+ import java .util .Map ;
20+ import java .util .Set ;
21+
1822import org .slf4j .Logger ;
1923import org .slf4j .LoggerFactory ;
2024import org .springframework .context .ApplicationContext ;
2630import org .springframework .data .couchbase .core .mapping .CouchbasePersistentProperty ;
2731import org .springframework .data .couchbase .core .mapping .event .AfterSaveEvent ;
2832import org .springframework .data .couchbase .core .mapping .event .CouchbaseMappingEvent ;
33+ import org .springframework .data .couchbase .core .support .TemplateUtils ;
2934import org .springframework .data .couchbase .repository .support .MappingCouchbaseEntityInformation ;
3035import org .springframework .data .couchbase .repository .support .TransactionResultHolder ;
3136import org .springframework .data .couchbase .transaction .CouchbaseResourceHolder ;
3237import org .springframework .data .mapping .PersistentPropertyAccessor ;
3338import org .springframework .data .mapping .context .MappingContext ;
3439import org .springframework .data .mapping .model .ConvertingPropertyAccessor ;
35-
3640import org .springframework .util .ClassUtils ;
3741
38- import java .util .Map ;
39- import java .util .Set ;
42+ import com .couchbase .client .core .error .CouchbaseException ;
4043
4144public abstract class AbstractTemplateSupport {
4245
@@ -47,7 +50,8 @@ public abstract class AbstractTemplateSupport {
4750 ApplicationContext applicationContext ;
4851 static final Logger LOG = LoggerFactory .getLogger (AbstractTemplateSupport .class );
4952
50- public AbstractTemplateSupport (ReactiveCouchbaseTemplate template , CouchbaseConverter converter , TranslationService translationService ) {
53+ public AbstractTemplateSupport (ReactiveCouchbaseTemplate template , CouchbaseConverter converter ,
54+ TranslationService translationService ) {
5155 this .template = template ;
5256 this .converter = converter ;
5357 this .mappingContext = converter .getMappingContext ();
@@ -56,10 +60,8 @@ public AbstractTemplateSupport(ReactiveCouchbaseTemplate template, CouchbaseConv
5660
5761 abstract ReactiveCouchbaseTemplate getReactiveTemplate ();
5862
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 ) {
6365
6466 // this is the entity class defined for the repository. It may not be the class of the document that was read
6567 // 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
7981 // to unwrap. This results in List<String[]> being unwrapped past String[] to String, so this may also be a
8082 // Collection (or Array) of entityClass. We have no way of knowing - so just assume it is what we are told.
8183 // if this is a Collection or array, only the first element will be returned.
84+ final CouchbaseDocument converted = new CouchbaseDocument (id );
8285 Set <Map .Entry <String , Object >> set = ((CouchbaseDocument ) translationService .decode (source , converted ))
8386 .getContent ().entrySet ();
8487 return (T ) set .iterator ().next ().getValue ();
8588 }
8689
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+
8797 // 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
8999 // can be avoid by defining the argument as Long instead of long.
90100 // persistentEntity is still the (possibly abstract) class specified in the repository definition
91101 // 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+ }
94110 }
95111
96112 // 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
101117
102118 persistentEntity = couldBePersistentEntity (readEntity .getClass ());
103119
104- if (cas != 0 && persistentEntity .getVersionProperty () != null ) {
120+ if (cas != null && cas != 0 && persistentEntity .getVersionProperty () != null ) {
105121 accessor .setProperty (persistentEntity .getVersionProperty (), cas );
106122 }
107123 N1qlJoinResolver .handleProperties (persistentEntity , accessor , getReactiveTemplate (), id , scope , collection );
108124
109- if (holder != null ){
110- holder .transactionResultHolder (txResultHolder , (T )accessor .getBean ());
125+ if (holder != null ) {
126+ holder .transactionResultHolder (txResultHolder , (T ) accessor .getBean ());
111127 }
112128
113129 return accessor .getBean ();
@@ -117,13 +133,16 @@ CouchbasePersistentEntity couldBePersistentEntity(Class<?> entityClass) {
117133 if (ClassUtils .isPrimitiveOrWrapper (entityClass ) || entityClass == String .class ) {
118134 return null ;
119135 }
120- return mappingContext . getPersistentEntity ( entityClass );
121- }
122-
136+ try {
137+ return mappingContext . getPersistentEntity ( entityClass );
138+ } catch ( InaccessibleObjectException t ) {
123139
140+ }
141+ return null ;
142+ }
124143
125144 public <T > T applyResultBase (T entity , CouchbaseDocument converted , Object id , long cas ,
126- TransactionResultHolder txResultHolder , CouchbaseResourceHolder holder ) {
145+ TransactionResultHolder txResultHolder , CouchbaseResourceHolder holder ) {
127146 ConvertingPropertyAccessor <Object > accessor = getPropertyAccessor (entity );
128147
129148 final CouchbasePersistentEntity <?> persistentEntity = converter .getMappingContext ()
@@ -139,8 +158,8 @@ public <T> T applyResultBase(T entity, CouchbaseDocument converted, Object id, l
139158 accessor .setProperty (versionProperty , cas );
140159 }
141160
142- if (holder != null ){
143- holder .transactionResultHolder (txResultHolder , (T )accessor .getBean ());
161+ if (holder != null ) {
162+ holder .transactionResultHolder (txResultHolder , (T ) accessor .getBean ());
144163 }
145164 maybeEmitEvent (new AfterSaveEvent (accessor .getBean (), converted ));
146165 return (T ) accessor .getBean ();
@@ -202,7 +221,7 @@ private boolean canPublishEvent() {
202221 return this .applicationContext != null ;
203222 }
204223
205- public TranslationService getTranslationService (){
224+ public TranslationService getTranslationService () {
206225 return translationService ;
207226 }
208227}
0 commit comments