grails-core icon indicating copy to clipboard operation
grails-core copied to clipboard

Grails 7.0.0-M1 - difficulties applying default constraints in application.groovy

Open boardbloke opened this issue 10 months ago • 2 comments

Expected Behavior

No response

Actual Behaviour

Not completely sure of precise cause atm, but behaviour i was seeing was that application.groovy was not being merged into PropertySources and default constraints were not being applied.

Works if you bootRun

Also - related, but separate, if I include CXF's starter-jaxws as an implementation dependency, then, boitRun also fails - it seems the auto wiring of grailsapplication does not occur in DefaultContraintEvaluatorFactory so it doesn't wire in the default constraints. If I take that starter out, and just use CXF classes the grailApplication is correctly injected

I'll try to find time to produce a minimal criminal, and attach

In the meantime, I worked around the application.groovy issue by creating a listener similar to that used in external-config library to manually load appliccation.groovy, slurp it and create a PropertySource which I add to the end of the list

Steps To Reproduce

Built a web based Grails app with a domain class

Have a application.yml and application.groovy in grails-app/conf

In application.groovy have a grails.gorm.default.constraints closure

Run in Tomcat with an external application.properties with the its location specified as a Spring.config.location

Environment Information

No response

Example Application

No response

Version

7.0.0-M1

boardbloke avatar Feb 22 '25 07:02 boardbloke

Attached is a bad app in a zip file. You need Make and docker installed to follow the steps below.

Unzip and in root directory run make docker-image to build a war and then put it in a docker image that runs tomcat

You can run the image with make docker-run

Once its started if you go to http://localhost:8080/badapp/test/index then you will see 0 test records If you then go to http://localhost:8080/badapp/test/save it should record 2 test records being saved, but in tomcat it only records 1.

The reason is that the application.groovy in the war is not loaded when the app starts, so the default constraints included in that file do not get added to the domain classes. One of the test record saves has a null property, so that save fails.

This works if you run using bootRun. The application.groovy is added to the PropertySources, and so the default constraints are applied.

Finally - the build.gradle contains a commented out ref to implementation "org.apache.cxf:cxf-spring-boot-starter-jaxws:4.1.0" If that is uncommented - then the default constraints are not applied. If you debug you see that DefaultConstraintEvaluatorFactoryBean.getObject is called but with that cxf dependency applied, the grailApplication object is null so the default constraint config is not available to be applied

badapp.zip

boardbloke avatar Feb 22 '25 11:02 boardbloke

Thank you @boardbloke for reporting this. We've added it to the next milestone.

For reference, here's the gradle dependency graph of the library that causes the problem:

	\--- org.apache.cxf:cxf-spring-boot-starter-jaxws:4.1.0
	     +--- org.springframework.boot:spring-boot-starter:3.4.0 -> 3.4.1 (*)
	     +--- org.springframework.boot:spring-boot-starter-web:3.4.0 -> 3.4.1 (*)
	     +--- org.apache.cxf:cxf-spring-boot-autoconfigure:4.1.0
	     |    \--- org.springframework.boot:spring-boot-autoconfigure:3.4.0 -> 3.4.1 (*)
	     +--- org.apache.cxf:cxf-rt-transports-http:4.1.0
	     |    \--- org.apache.cxf:cxf-core:4.1.0
	     |         +--- jakarta.annotation:jakarta.annotation-api:2.1.1
	     |         +--- org.glassfish.jaxb:jaxb-runtime:4.0.5 (*)
	     |         +--- com.fasterxml.woodstox:woodstox-core:7.1.0
	     |         |    \--- org.codehaus.woodstox:stax2-api:4.2.2
	     |         +--- org.apache.ws.xmlschema:xmlschema-core:2.3.1
	     |         +--- org.eclipse.angus:angus-activation:2.0.2
	     |         |    \--- jakarta.activation:jakarta.activation-api:2.1.3
	     |         \--- jakarta.xml.bind:jakarta.xml.bind-api:4.0.2 (*)
	     +--- org.apache.cxf:cxf-rt-frontend-jaxws:4.1.0
	     |    +--- xml-resolver:xml-resolver:1.2
	     |    +--- org.ow2.asm:asm:9.7.1
	     |    +--- org.apache.cxf:cxf-core:4.1.0 (*)
	     |    +--- org.apache.cxf:cxf-rt-bindings-soap:4.1.0
	     |    |    +--- jakarta.xml.soap:jakarta.xml.soap-api:3.0.2
	     |    |    |    \--- jakarta.activation:jakarta.activation-api:2.1.3
	     |    |    +--- jakarta.jws:jakarta.jws-api:3.0.0
	     |    |    +--- jakarta.xml.ws:jakarta.xml.ws-api:4.0.2
	     |    |    |    +--- jakarta.xml.bind:jakarta.xml.bind-api:4.0.2 (*)
	     |    |    |    \--- jakarta.xml.soap:jakarta.xml.soap-api:3.0.2 (*)
	     |    |    +--- org.apache.cxf:cxf-core:4.1.0 (*)
	     |    |    +--- org.apache.cxf:cxf-rt-wsdl:4.1.0
	     |    |    |    +--- org.apache.cxf:cxf-core:4.1.0 (*)
	     |    |    |    +--- wsdl4j:wsdl4j:1.6.3
	     |    |    |    \--- org.ow2.asm:asm:9.7.1
	     |    |    +--- org.apache.cxf:cxf-rt-databinding-jaxb:4.1.0
	     |    |    |    +--- org.apache.cxf:cxf-core:4.1.0 (*)
	     |    |    |    \--- org.apache.cxf:cxf-rt-wsdl:4.1.0 (*)
	     |    |    \--- org.eclipse.angus:angus-activation:2.0.2 (*)
	     |    +--- org.apache.cxf:cxf-rt-bindings-xml:4.1.0
	     |    |    \--- org.apache.cxf:cxf-core:4.1.0 (*)
	     |    +--- org.apache.cxf:cxf-rt-frontend-simple:4.1.0
	     |    |    +--- org.apache.cxf:cxf-core:4.1.0 (*)
	     |    |    +--- org.apache.cxf:cxf-rt-bindings-soap:4.1.0 (*)
	     |    |    +--- org.apache.cxf:cxf-rt-wsdl:4.1.0 (*)
	     |    |    \--- org.eclipse.angus:angus-mail:2.0.3
	     |    |         +--- jakarta.activation:jakarta.activation-api:2.1.3
	     |    |         \--- jakarta.mail:jakarta.mail-api:2.1.3
	     |    |              \--- jakarta.activation:jakarta.activation-api:2.1.3
	     |    +--- org.apache.cxf:cxf-rt-ws-addr:4.1.0
	     |    |    +--- org.apache.cxf:cxf-core:4.1.0 (*)
	     |    |    +--- org.apache.cxf:cxf-rt-bindings-soap:4.1.0 (*)
	     |    |    \--- org.apache.cxf:cxf-rt-ws-policy:4.1.0
	     |    |         +--- wsdl4j:wsdl4j:1.6.3
	     |    |         +--- org.apache.cxf:cxf-core:4.1.0 (*)
	     |    |         \--- org.apache.neethi:neethi:3.2.1
	     |    \--- org.eclipse.angus:angus-activation:2.0.2 (*)
	     +--- org.apache.cxf:cxf-rt-features-metrics:4.1.0
	     |    +--- jakarta.xml.ws:jakarta.xml.ws-api:4.0.2 (*)
	     |    \--- org.apache.cxf:cxf-core:4.1.0 (*)
	     +--- jakarta.validation:jakarta.validation-api:3.0.2
	     \--- org.springframework.boot:spring-boot-starter-validation:3.4.0 -> 3.4.1 (*)

jdaugherty avatar Mar 14 '25 02:03 jdaugherty

Hi @boardbloke ,

I took your example application, and updated it for Grails 7 (latest snapshot). I then published it here: https://github.com/jdaugherty/grails-issue-14035

When I uncomment the CXF dependency, it works locally. Can you please confirm that this bad behavior was only noticeable when run inside of the container if uncommented? Did it always work in bootRun 100% of the time?

Please note: we've upgraded Spring since this was originally reported and are now on a later version than CXF so that may be why it's working now.

-James

jdaugherty avatar Jul 06 '25 20:07 jdaugherty

@boardbloke Is this still occurring with 7.0.0-RC1?

jamesfredley avatar Aug 20 '25 23:08 jamesfredley

Hi @boardbloke ,

I took your example application, and updated it for Grails 7 (latest snapshot). I then published it here: https://github.com/jdaugherty/grails-issue-14035

When I uncomment the CXF dependency, it works locally. Can you please confirm that this bad behavior was only noticeable when run inside of the container if uncommented? Did it always work in bootRun 100% of the time?

Please note: we've upgraded Spring since this was originally reported and are now on a later version than CXF so that may be why it's working now.

-James

Hi @jdaugherty , @jamesfredley - yes that was the behavior - worked via bootRun - didn't work when run as a war in a container.

I've submitted a PR to https://github.com/jdaugherty/grails-issue-14035 to upgrade the bad app to 7.0.0-RC1 - (https://github.com/jdaugherty/grails-issue-14035/pull/1) and its still occurring.

This time around though, inclusion of the CXF library makes no difference to boorWar's behaviour, so I've deleted that.

In latest bad app, bootRun works as expected and war file via Tomcat in a container does not.

Steps to reproduce for the latest bad app are the same as above make docker-build followed by make docker-run

boardbloke avatar Aug 21 '25 13:08 boardbloke

Thank you!

jdaugherty avatar Aug 21 '25 13:08 jdaugherty

@boardbloke My first thought was this is something docker is doing to the war contents based on what we saw on https://github.com/wondrify/asset-pipeline/issues/373 and after removing docker from the equation, which I always take as a first step, I think docker is the difference. Please take a look at /WEB-INF/classes/ and see if application.groovy and application.yml are present after running docker build -t badapp:0.2-SNAPSHOT ./docker

locally I tested this with bootRun and with bootWar + java -jar badapp-0.2.war after changing the following in application.yml

  production:
    dataSource:
      dbCreate: create-drop
      url: jdbc:h2:mem:prodDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE

Both save two Example instances with application.groovy as is and both only save one Example instance with application.groovy commented out. That confirms that application.groovy appears to be the variable, but given this works with bootRun and with bootWar + java -jar badapp-0.2.war, see what docker is doing as a first step.

jamesfredley avatar Aug 22 '25 17:08 jamesfredley

Hi @jamesfredley - found it. Operator error!

In the tomcat config is was pulling in an external file via spring.config.location when I should be using spring.config.additional-location. The former replaces default property sources (so application.groovy was not loaded)

https://docs.spring.io/spring-boot/reference/features/external-config.html "Locations configured by using spring.config.location replace the default locations."

Using the proper spring property fixed it.

Forehead slap!

Thanks very much for the support - glad its me and nothing more serious!

boardbloke avatar Aug 23 '25 11:08 boardbloke

This issue can be closed as not a bug! :-)

boardbloke avatar Aug 23 '25 11:08 boardbloke

@boardbloke All good, glad you found it and it is resolved.

jamesfredley avatar Aug 23 '25 13:08 jamesfredley