Skip to content

Commit a2e3bd4

Browse files
committed
Merge branch '7.0.x' into add-graalvm-versions
# Conflicts: # grails-bom/build.gradle
2 parents 75f292b + fd3dde5 commit a2e3bd4

File tree

58 files changed

+2319
-64
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2319
-64
lines changed

build.gradle

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,26 @@ subprojects { subproject ->
191191
group = 'org.grails'
192192
}
193193

194+
if(isExample) {
195+
// Test projects will often include dependencies from grails-core, this file will ensure any dependencies included
196+
// will be substituted with projects in this repository instead of pulling upstream
197+
configurations.all {
198+
resolutionStrategy {
199+
dependencySubstitution {
200+
for (def possibleProject : rootProject.subprojects) {
201+
if(!possibleProject.name.startsWith('grails-test-suite') && !possibleProject.name.contains('grails-test-examples') && possibleProject.name != 'grails-bom') {
202+
def artifactId = mappedArtifactIds[possibleProject.name] ?: possibleProject.name
203+
substitute module("${subproject.name in ['grails-async-plugin', 'grails-events-plugin'] ? 'org.grails.plugins' : 'org.grails'}:${artifactId}") using project(":${possibleProject.name}")
204+
}
205+
}
206+
}
207+
}
208+
}
209+
}
210+
194211
ext.pomInfo = {
195212
delegate.name 'Grails® framework'
196-
delegate.description 'Grails Web Application Framework'
213+
delegate.description subproject.name == 'grails-testing-support' ? 'Support for writing concise expressive tests for Grails artifacts' : 'Grails Web Application Framework'
197214
delegate.url 'https://grails.org/'
198215

199216
delegate.licenses {
@@ -210,11 +227,25 @@ subprojects { subproject ->
210227
delegate.developerConnection 'scm:[email protected]:grails/grails-core.git'
211228
}
212229

213-
delegate.developers {
214-
delegate.developer {
215-
delegate.id 'graemerocher'
216-
delegate.name 'Graeme Rocher'
217-
delegate.email '[email protected]'
230+
if(subproject.name == 'grails-testing-support') {
231+
delegate.developers {
232+
delegate.developer {
233+
delegate.id 'jeffscottbrown'
234+
delegate.name 'Jeff Brown'
235+
}
236+
delegate.developer {
237+
delegate.id 'jameskleeh'
238+
delegate.name 'James Kleeh'
239+
}
240+
}
241+
}
242+
else {
243+
delegate.developers {
244+
delegate.developer {
245+
delegate.id 'graemerocher'
246+
delegate.name 'Graeme Rocher'
247+
delegate.email '[email protected]'
248+
}
218249
}
219250
}
220251
}
@@ -374,8 +405,6 @@ subprojects { subproject ->
374405
testImplementation "org.junit.platform:junit-platform-runner"
375406
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine"
376407

377-
compileOnly "com.github.spotbugs:spotbugs-annotations"
378-
379408
if (subproject.name != "grails-docs") {
380409
// Logging
381410
api "org.slf4j:slf4j-api"

dependabot/build.gradle

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ dependencies {
1414
api "net.bytebuddy:byte-buddy:${project['byte-buddy.version']}"
1515
api "commons-codec:commons-codec:${project['commons-codec.version']}"
1616
api "org.apache.commons:commons-text:${project['commons-text.version']}"
17-
api "org.grails.plugins:converters:${project['converters.version']}"
1817
api "io.methvin:directory-watcher:${project['directory-watcher.version']}"
1918
api "org.xhtmlrenderer:flying-saucer-pdf-openpdf:${project['flying-saucer-pdf-openpdf.version']}"
2019
api "org.gebish:geb-spock:${project['geb-spock.version']}"
@@ -36,7 +35,6 @@ dependencies {
3635
api "org.grails:grails-gdoc-engine:${project['grails-gdoc-engine.version']}"
3736
api "org.grails:grails-gradle-plugin:${project['grails-gradle-plugin.version']}"
3837
api "org.grails:grails-gorm-testing-support:${project['grails-testing-support.version']}"
39-
api "org.grails:grails-testing-support:${project['grails-testing-support.version']}"
4038
api "org.grails:grails-web-testing-support:${project['grails-testing-support.version']}"
4139
api "org.apache.groovy:groovy-bom:${project['groovy.version']}"
4240
api "org.grails:grails-gsp:${project['gsp.version']}"
@@ -82,7 +80,6 @@ dependencies {
8280
api "org.grails.profiles:web:${project['profiles-web.version']}"
8381
api "org.spockframework:spock-core:${project['spock.version']}"
8482
api "org.spockframework:spock-spring:${project['spock.version']}"
85-
api "com.github.spotbugs:spotbugs-annotations:${project['spotbugs-annotations.version']}"
8683
api "org.springframework.boot:spring-boot-cli:${project['spring-boot.version']}"
8784
api "org.springframework.boot:spring-boot-gradle-plugin:${project['spring-boot.version']}"
8885
api "org.springframework:springloaded:${project['springloaded.version']}"

gradle.properties

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ plexusComponentApiVersion=1.0-alpha-33
1515
plexusSecDispatcherVersion=1.4
1616
plexusSisuInjectVersion=2.6.0
1717
slf4jVersion=2.0.16
18-
rxJava1Version=1.3.8
19-
rxJava2Version=2.2.21
2018
gparsVersion=1.2.1
2119

2220
org.gradle.caching=true
@@ -32,7 +30,7 @@ preventSnapshotPublish=false
3230
# https://github.com/grails/grails-gradle-plugin/issues/222
3331
slf4jPreventExclusion=true
3432

35-
# Generated on Tue Jan 07 15:14:48 EST 2025 by: ./gradlew :grails-bom:syncProps
33+
# Generated on Thu Jan 16 10:23:54 EST 2025 by: ./gradlew :grails-bom:syncProps
3634
# Only version value modifications allowed after this point. Do not insert or change version names.
3735
ant.version=1.10.15
3836
asciidoctorj.version=3.0.0
@@ -43,7 +41,6 @@ bootstrap-icons.version=1.11.3
4341
byte-buddy.version=1.15.5
4442
commons-codec.version=1.17.1
4543
commons-text.version=1.12.0
46-
converters.version=6.0.0-SNAPSHOT
4744
directory-watcher.version=0.18.0
4845
flying-saucer-pdf-openpdf.version=9.4.0
4946
geb-spock.version=7.0
@@ -53,7 +50,6 @@ grails-datastore-gorm-hibernate5.version=9.0.0-SNAPSHOT
5350
grails-datastore-gorm-mongodb.version=9.0.0-SNAPSHOT
5451
grails-gdoc-engine.version=1.0.1
5552
grails-gradle-plugin.version=7.0.0-SNAPSHOT
56-
grails-testing-support.version=4.0.0-SNAPSHOT
5753
groovy.version=4.0.24
5854
gsp.version=7.0.0-SNAPSHOT
5955
h2.version=2.3.232
@@ -73,8 +69,6 @@ plugins-geb.version=5.0.0-SNAPSHOT
7369
plugins-hibernate5.version=9.0.0-SNAPSHOT
7470
plugins-mongodb.version=9.0.0-SNAPSHOT
7571
plugins-neo4j.version=8.1.0
76-
plugins-rxjava.version=1.1.1
77-
plugins-rxjava2.version=2.0.0
7872
plugins-scaffolding.version=6.0.0-SNAPSHOT
7973
plugins-views-gradle.version=4.0.0-SNAPSHOT
8074
plugins-views-json.version=4.0.0-SNAPSHOT
@@ -90,8 +84,10 @@ profiles-rest-api-plugin.version=7.0.1
9084
profiles-vue.version=7.0.1
9185
profiles-web.version=7.0.1
9286
profiles-web-plugin.version=7.0.1
87+
rxjava.version=1.3.8
88+
rxjava2.version=2.2.21
89+
rxjava3.version=3.1.10
9390
spock.version=2.3-groovy-4.0
94-
spotbugs-annotations.version=4.8.6
9591
spring-boot.version=3.4.1
9692
springloaded.version=1.2.8.RELEASE
9793
views-json-testing-support.version=4.0.0-SNAPSHOT

grails-async/rxjava/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ dependencies {
22
implementation platform(project(':grails-bom'))
33

44
api project(':grails-async-core')
5-
api "io.reactivex:rxjava:$rxJava1Version"
5+
api "io.reactivex:rxjava"
66

77
implementation 'org.apache.groovy:groovy'
88
implementation 'org.slf4j:slf4j-api'

grails-async/rxjava2/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ dependencies {
22
implementation platform(project(':grails-bom'))
33

44
api project(':grails-async-core')
5-
api "io.reactivex.rxjava2:rxjava:$rxJava2Version"
5+
api "io.reactivex.rxjava2:rxjava"
66

77
implementation 'org.apache.groovy:groovy'
88
implementation 'org.slf4j:slf4j-api'

grails-async/rxjava2/src/main/groovy/org/grails/async/factory/rxjava2/RxPromise.groovy

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@ class RxPromise<T> implements Promise<T> {
4141
protected boolean finished = false
4242

4343
RxPromise(RxPromiseFactory promiseFactory, Closure callable, Scheduler scheduler) {
44+
4445
this(promiseFactory, Single.create( { SingleEmitter<? super T> singleSubscriber ->
4546
try {
46-
singleSubscriber.onSuccess((T)callable.call())
47+
singleSubscriber.onSuccess((T)runCallable(callable))
4748
} catch (Throwable t) {
4849
singleSubscriber.onError(t)
4950
}
@@ -158,4 +159,13 @@ class RxPromise<T> implements Promise<T> {
158159
}
159160
}
160161
}
162+
163+
static Object runCallable(Closure callable) {
164+
Object rtn = callable.call()
165+
if(rtn == null) {
166+
return Void
167+
} else {
168+
return rtn
169+
}
170+
}
161171
}

grails-async/rxjava2/src/test/groovy/org/grails/async/factory/rxjava2/RxPromiseSpec.groovy

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,18 @@ class RxPromiseSpec extends Specification {
5454
result == [one: 1, two: 2, four: 4]
5555
}
5656

57+
void 'Test promise null handling'() {
58+
59+
when: 'a null promise result is created'
60+
def promise = Promises.createPromise {
61+
return null
62+
}
63+
def result = promise.get()
64+
65+
then: 'result is void'
66+
result == Void
67+
}
68+
5769
void 'Test promise list handling'() {
5870

5971
when: 'a promise list is created from two promises'

grails-async/rxjava3/build.gradle

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
dependencies {
2+
implementation platform(project(':grails-bom'))
3+
4+
api project(':grails-async-core')
5+
api "io.reactivex.rxjava3:rxjava"
6+
7+
implementation 'org.apache.groovy:groovy'
8+
implementation 'org.slf4j:slf4j-api'
9+
10+
testImplementation 'org.spockframework:spock-core'
11+
12+
testRuntimeOnly 'org.slf4j:slf4j-nop' // Get rid of warning about missing slf4j implementation during test task
13+
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package org.grails.async.factory.rxjava3
2+
3+
import grails.async.Promise
4+
import groovy.transform.AutoFinal
5+
import groovy.transform.CompileStatic
6+
import groovy.transform.PackageScope
7+
import io.reactivex.rxjava3.core.Observable
8+
import io.reactivex.rxjava3.core.Observer
9+
import io.reactivex.rxjava3.core.Scheduler
10+
import io.reactivex.rxjava3.core.Single
11+
import io.reactivex.rxjava3.core.SingleEmitter
12+
import io.reactivex.rxjava3.core.SingleOnSubscribe
13+
import io.reactivex.rxjava3.disposables.Disposable
14+
import io.reactivex.rxjava3.functions.Consumer
15+
import io.reactivex.rxjava3.functions.Function
16+
import io.reactivex.rxjava3.subjects.ReplaySubject
17+
import io.reactivex.rxjava3.subjects.Subject
18+
import org.grails.async.factory.BoundPromise
19+
20+
import java.util.concurrent.ExecutionException
21+
import java.util.concurrent.TimeUnit
22+
import java.util.concurrent.TimeoutException
23+
24+
/**
25+
* Promise based on RxJava 3.x
26+
*
27+
* @since 7.0
28+
*/
29+
@AutoFinal
30+
@CompileStatic
31+
@PackageScope
32+
class RxPromise<T> implements Promise<T> {
33+
34+
protected final Subject<T> subject
35+
protected final RxPromiseFactory promiseFactory
36+
protected final Observable<T> observable
37+
38+
protected Disposable subscription
39+
protected boolean finished = false
40+
41+
RxPromise(RxPromiseFactory promiseFactory, Closure callable, Scheduler scheduler) {
42+
this(promiseFactory, Single.create( { SingleEmitter<? super T> singleSubscriber ->
43+
try {
44+
singleSubscriber.onSuccess((T)runCallable(callable))
45+
} catch (Throwable t) {
46+
singleSubscriber.onError(t)
47+
}
48+
} as SingleOnSubscribe<T>)
49+
.subscribeOn(scheduler))
50+
}
51+
52+
RxPromise(RxPromiseFactory promiseFactory, Observable single) {
53+
this(promiseFactory, single, ReplaySubject.create(1))
54+
}
55+
56+
RxPromise(RxPromiseFactory promiseFactory, Single single) {
57+
this(promiseFactory, single, ReplaySubject.create(1))
58+
}
59+
60+
RxPromise(RxPromiseFactory promiseFactory, Single single, Subject subject) {
61+
this(promiseFactory, single.toObservable(), subject)
62+
}
63+
64+
RxPromise(RxPromiseFactory promiseFactory, Observable observable, Subject subject) {
65+
this.observable = observable
66+
this.promiseFactory = promiseFactory
67+
observable.subscribe(new Observer<T>() {
68+
@Override
69+
void onSubscribe(Disposable d) {
70+
subscription = d
71+
}
72+
73+
@Override
74+
void onNext(T t) {
75+
subject.onNext(t)
76+
}
77+
78+
@Override
79+
void onError(Throwable e) {
80+
subject.onError(e)
81+
}
82+
83+
@Override
84+
void onComplete() {
85+
finished = true
86+
}
87+
})
88+
this.subject = subject
89+
}
90+
91+
Observable<T> toObservable() {
92+
return this.observable
93+
}
94+
95+
@Override
96+
Promise<T> accept(T value) {
97+
return new BoundPromise<T>(value)
98+
}
99+
100+
@Override
101+
Promise<T> onComplete(Closure<T> callable) {
102+
def decoratedCallable = promiseFactory.applyDecorators(callable, null)
103+
return new RxPromise<T>(promiseFactory, subject.map(decoratedCallable as Function<T, T>))
104+
}
105+
106+
@Override
107+
Promise<T> onError(Closure<T> callable) {
108+
def decoratedCallable = promiseFactory.applyDecorators(callable, null)
109+
return new RxPromise<T>(promiseFactory, subject.doOnError(decoratedCallable as Consumer<Throwable>))
110+
}
111+
112+
@Override
113+
Promise<T> then(Closure<T> callable) {
114+
return onComplete(callable)
115+
}
116+
117+
@Override
118+
boolean cancel(boolean mayInterruptIfRunning) {
119+
if(subscription != null) {
120+
subscription.dispose()
121+
return subscription.isDisposed()
122+
}
123+
return false
124+
}
125+
126+
@Override
127+
boolean isCancelled() {
128+
if(subscription == null) {
129+
return false
130+
}
131+
else {
132+
return subscription.isDisposed()
133+
}
134+
}
135+
136+
@Override
137+
boolean isDone() {
138+
return finished
139+
}
140+
141+
@Override
142+
T get() throws InterruptedException, ExecutionException {
143+
return subject.blockingFirst()
144+
}
145+
146+
@Override
147+
T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
148+
try {
149+
return subject.timeout(timeout, unit).blockingFirst()
150+
} catch (Throwable e) {
151+
if(e.cause instanceof TimeoutException) {
152+
throw e.cause
153+
}
154+
else {
155+
throw e
156+
}
157+
}
158+
}
159+
160+
static Object runCallable(Closure callable) {
161+
Object rtn = callable.call()
162+
if(rtn == null) {
163+
return Void
164+
} else {
165+
return rtn
166+
}
167+
}
168+
}

0 commit comments

Comments
 (0)