jdaugherty opened a new issue, #16692:
URL: https://github.com/apache/grails-core/issues/16692

   ### Summary
   
   A GORM data service method that returns an `Observable` of a scalar property 
projection fails at runtime with a `GroovyCastException`: the single projected 
value is cast to an `Iterable`. The same projection declared as a `Single` 
works.
   
   ### Steps to reproduce
   
   ```groovy
   @Entity
   class Book {
       String title
       String author
   }
   
   @Service(Book)
   interface BookSingleService {
       Single<String> findBookAuthor(String title)        // works
   }
   
   @Service(Book)
   interface BookObservableService {
       Observable<String> findBookAuthor(String title)    // fails
   }
   ```
   
   ```groovy
   new Book(title: 'The Stand', author: 'Stephen King').save(flush: true)
   
   datastore.getService(BookSingleService).findBookAuthor('The 
Stand').blockingGet()            // 'Stephen King'
   datastore.getService(BookObservableService).findBookAuthor('The 
Stand').toList().blockingGet() // throws
   ```
   
   Run as a throwaway spec in `grails-datamapping-core-test` against a 
`SimpleMapDatastore`, as `RxServiceImplSpec` does.
   
   There is no spelling that works for an `Observable` of a scalar projection: 
`Observable<String> findAllBookAuthor(String title)` is rejected at compile 
time with `No implementations possible for method 
'findAllBookAuthor(java.lang.String):io.reactivex.rxjava3.core.Observable'`, so 
only the `find` form matches an implementer, and that one fails at runtime.
   
   ### Actual behaviour
   
   ```
   org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast 
object 'Stephen King' with class 'java.lang.String' to class 
'java.lang.Iterable'
        at 
grails.gorm.transactions.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:139)
        at 
org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:137)
        at 
grails.gorm.transactions.GrailsTransactionTemplate.doExecute(GrailsTransactionTemplate.groovy:136)
        at 
grails.gorm.transactions.GrailsTransactionTemplate.execute_closure2(GrailsTransactionTemplate.groovy:131)
        at 
grails.gorm.transactions.GrailsTransactionTemplate.inConnectionScope(GrailsTransactionTemplate.groovy:96)
        at 
grails.gorm.transactions.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:131)
        at 
org.grails.gorm.rx.services.support.RxServiceSupport.create_closure1(RxServiceSupport.groovy:62)
        at 
io.reactivex.rxjava3.internal.operators.observable.ObservableDefer.subscribeActual(ObservableDefer.java:33)
        ...
        at io.reactivex.rxjava3.core.Single.blockingGet(Single.java:3644)
   ```
   
   ### Expected behaviour
   
   An `Observable<String>` emits the projected value (or every projected value 
for a multi-valued query) and completes, in the same way `Single<String>` 
delivers one.
   
   ### Where it comes from
   
   `ObservableResultAdapter` (`grails-datamapping-rx`, 
`org.grails.gorm.rx.services.implementers`) adapts every 
`IterableServiceImplementer` to an `Observable` return type. `doesImplement` 
accepts the method for an `IterableProjectionServiceImplementer` when the 
prefix matches (`find`) and the projection is compatible with 
`Iterable<String>`, and `implement` then narrows the synchronous return type to 
`Iterable<String>` before delegating, so the generated body is typed as 
returning an `Iterable` while the adapted projection implementer returns the 
single value. `RxServiceSupport.create` would handle a scalar 
(`Observable.just`) if it ever received one, but the cast in the generated, 
transactional body fails first.
   
   ### Affected versions
   
   Reproduced on `9.0.x` (RxJava 3, at the head of #16619) and on `8.1.x` 
(RxJava 1, `bd0c1394ce`'s successor at the branch head), with the same 
`GroovyCastException` from the data service body in both. 
`grails-datamapping-rx` is not part of the build on `7.0.x`, `7.2.x` or `8.0.x` 
(`settings.gradle` has it commented out there), so the module, and with it this 
bug, ships from 8.1 on.
   
   Found by @codeconsole while reviewing #16619, where the data services moved 
to RxJava 3; the failure is the same on RxJava 1, so it is not caused by that 
change.
   
   @borinquenkid, could you take a look at this one?
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to