Issues with Grails 3 domain class named "Application" - grails

I have a legacy system that I am migrating to Grails 3 but I'm running into a naming convention issue. One of our tables is called Application but that is also the name of the Groovy class that runs the application. There seems to be an issue where GORM is confusing the 2 classes and giving type-casting errors. I have tried explicitly casting my Application class in my ApplicationDegree class to try and force GORM to recognize which class I am trying to use but no success.
I know an option is that I can rename my domain Application class to something else and manually map it to the appropriate database table but I want to avoid that as I foresee issues down the road.
So, other than renaming my Domain classes, how can I get Grails/GORM to make the correct mapping.
Grails 3.1.4
Code:
ApplicationDegree ad = ApplicationDegree.findById(10);
Class:
class ApplicationDegree {
Boolean isPrimary
domain.package.Application application
Degree degree
static hasMany = [applicationDegreeMajors: ApplicationDegreeMajor,
applicationDegreeMinors: ApplicationDegreeMinor]
static belongsTo = [domain.package.Application, Degree]
static mapping = {
version false
degree column: 'degree_code'
isPrimary column: 'isPrimary'
}
}
StackTrace:
ERROR org.grails.spring.beans.factory.OptimizedAutowireCapableBeanFactory - Bean couldn't be autowired using grails optimization: Property 'application' threw exception; nested exception is java.lang.IllegalArgumentException: argument type mismatch
ERROR org.grails.spring.beans.factory.OptimizedAutowireCapableBeanFactory - Retrying using spring autowire
ERROR org.grails.web.errors.GrailsExceptionResolver - IllegalStateException occurred when processing request: [GET] /app4grad_V2/college/applications/
Cannot convert value of type [app4grad.Application] to required type [domain.package.Application] for property 'application': no matching editors or conversion strategy found. Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.InstantiationException: Could not instantiate entity: : domain.package.ApplicationDegree
at app4grad.college.ApplicationsController$$EPuFyMDe.index(ApplicationsController.groovy:14)
... 3 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
... 4 common frames omitted
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type [app4grad.Application] to required type [domain.package.Application] for property 'application'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [app4grad.Application] to required type [domain.package.Application] for property 'application': no matching editors or conversion strategy found
... 4 common frames omitted
Caused by: java.lang.IllegalStateException: Cannot convert value of type [app4grad.Application] to required type [domain.package.Application] for property 'application': no matching editors or conversion strategy found
... 4 common frames omitted

I had the same problem, the problem is that you're using a reserved name : https://grails.org/wiki/Reserved%20Names
Using Intelij Idea you can easily rename you're domain class and the IDE will do the rest for you.

Related

Grails 3 domain composition using #Delegate

In my app I have a set of 1000 or so "HouseProto" domain objects, which have a bunch of static properties that I need in my "HouseInstance" object.
At scale, maybe there are large numbers of HouseInstance objects each modeled on the HouseProtos. Here is how I tried to model the HouseInstance domain object.
class HouseInstance {
#Delegate
HouseProto houseProto
User agent
static belongsTo=[world: World]
static constraints = {
agent nullable:true
}
}
HouseProto has a lot of fields like "squareFeet" and "bedroomCount" etc.
I used the #Delegate annotation because I'd like to be able to do something like
houseInstance.streetAddress
instead of
houseInstance.houseProto.streetAddress
but this fails on compile. Buried at the end of the console output below is a reference to the "features" field of HouseProto (a hasMany Set) which suggests that might have something to do with it. Remove the delegate annotation, though and it all works fine. (Feature is a domain class that belongsTo HouseProto.)
My question is simply whether or not the #Delegate annotation is incompatible with Domain classes because it interferes with GORM for some reason? It seems like it will do what I want if it can be made to compile.
HouseProto looks more or less like this:
class HouseProto {
def houseService
String streetAddress
Owner owner
Integer sqft
Double acreage
Integer bedroom
...
Double kitchenQuality =0
Double loanBalance =0
Neighborhood neighborhood
String toString() {
"$streetAddress"
}
static hasMany = [features: Feature]
static constraints = {
streetAddress nullable: false, unique: true;
owner nullable: true
sqft nullable: false
neighborhood nullable: false
}
}
The runtime console output starts with this:
ERROR org.springframework.boot.context.embedded.tomcat.TomcatStarter - Error starting Tomcat context. Exception: org.springframework.beans.factory.BeanCreationException. Message: Error creating bean with name 'grailsCacheFilter': Cannot create inner bean '(inner bean)#5ec1152d' of type [grails.plugin.cache.web.filter.simple.MemoryPageFragmentCachingFilter] while setting bean property 'filter'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name '(inner bean)#5ec1152d': Unsatisfied dependency expressed through method 'setUrlMappingsHandlerMapping' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'urlMappingsHandlerMapping': Unsatisfied dependency expressed through method 'setWebRequestInterceptors' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'openSessionInViewInterceptor': Cannot resolve reference to bean 'hibernateDatastore' while setting bean property 'hibernateDatastore'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hibernateDatastore': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.grails.orm.hibernate.HibernateDatastore]: Constructor threw exception; nested exception is org.hibernate.MappingException: collection element mapping has wrong number of columns: com.grapevine.negotiator2.HouseInstance.features type: object
Disconnected from the target VM, address: '127.0.0.1:57570', transport: 'socket'
ERROR org.springframework.boot.SpringApplication - Application startup failed
As far as I aware #Delegate is not supported in domains, you may have more luck using a trait that both HouseInstance and HouseProto implement

Convert org.apache.tomcat.jdbc.pool.DataSource to org.apache.commons.dbcp.BasicDataSource

Upgrading from Grails 2.2.1 to 2.4.3 everything else has upgraded fine, but having an issue with the Tomcat upgrade to 7.0.54 I am getting an error of
Error initializing the application: Error creating bean with name
'dataSourceMBean': Unsatisfied dependency expressed through
constructor argument with index 0 of type
[org.apache.commons.dbcp.BasicDataSource]: Could not convert
constructor argument value of type
[org.apache.tomcat.jdbc.pool.DataSource] to required type
[org.apache.commons.dbcp.BasicDataSource]: Failed to convert value of
type 'org.apache.tomcat.jdbc.pool.DataSource' to required type
'org.apache.commons.dbcp.BasicDataSource'; nested exception is
java.lang.IllegalStateException: Cannot convert value of type
[org.apache.tomcat.jdbc.pool.DataSource] to required type
[org.apache.commons.dbcp.BasicDataSource]: no matching editors or
conversion strategy found
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'dataSourceMBean': Unsatisfied
dependency expressed through constructor argument with index 0 of type
[org.apache.commons.dbcp.BasicDataSource]: Could not convert
constructor argument value of type
[org.apache.tomcat.jdbc.pool.DataSource] to required type
[org.apache.commons.dbcp.BasicDataSource]: Failed to convert value of
type 'org.apache.tomcat.jdbc.pool.DataSource' to required type
'org.apache.commons.dbcp.BasicDataSource'; nested exception is
java.lang.IllegalStateException: Cannot convert value of type
[org.apache.tomcat.jdbc.pool.DataSource] to required type
[org.apache.commons.dbcp.BasicDataSource]: no matching editors or
conversion strategy found
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:722)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1114)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1017)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.codehaus.groovy.grails.commons.spring.DefaultRuntimeSpringConfiguration.getApplicationContext(DefaultRuntimeSpringConfiguration.java:156)
at org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator.initializeContext(GrailsRuntimeConfigurator.java:188)
at org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator.configure(GrailsRuntimeConfigurator.java:168)
at org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator.configure(GrailsRuntimeConfigurator.java:127)
at org.codehaus.groovy.grails.web.context.GrailsConfigUtils.configureWebApplicationContext(GrailsConfigUtils.java:126)
at org.codehaus.groovy.grails.web.context.GrailsContextLoaderListener.initWebApplicationContext(GrailsContextLoaderListener.java:109)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4973)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
The area that I am getting the error in has been around for a while
dataSourceMBean(com.item.management.DataSourceMBean, ref('dataSourceUnproxied'))
The class is:
class DataSourceMBean {
private BasicDataSource dataSource
public DataSourceMBean(BasicDataSource dataSource) {
this.dataSource = dataSource
}
When I change the dataSource to to a specific type :
private org.apache.tomcat.jdbc.pool.DataSource dataSource
Everything compiles and all tests run fine.
Asking when did this change?
Is there an alternative to the BasicDataSource I should be using instead?
I found this article but, not sure if applies
java.lang.ClassCastException: org.apache.tomcat.dbcp.dbcp.BasicDataSource cannot be cast to org.apache.tomcat.jdbc.pool.DataSource
Unless you really need it to be a BasicDataSource (and I can't see why you would), don't change it to a more specific class, change it to the interface, javax.sql.DataSource. If you do need a particular implementation class, you can define your own dataSource bean by registering a org.apache.commons.dbcp.BasicDataSource in resources.groovy and setting whatever properties are needed, e.g.
import org.apache.commons.dbcp.BasicDataSource
beans = {
dataSourceUnproxied(BasicDataSource) {
driverClassName = 'foo'
username = 'bar'
password = 'secret'
url = 'the_url'
...
}
...
}
You can do this with any bean registered by Grails or a plugin as long as you use the same bean name.

How to fix Dataflow unable to serialize my DoFn?

When I run my Dataflow pipeline, I get the exception below complaining that my DoFn can't be serialized. How do I fix this?
Here's the stack trace:
Caused by: java.lang.IllegalArgumentException: unable to serialize contrail.dataflow.AvroMRTransforms$AvroReducerDoFn#bba0fc2
at com.google.cloud.dataflow.sdk.util.SerializableUtils.serializeToByteArray(SerializableUtils.java:51)
at com.google.cloud.dataflow.sdk.util.SerializableUtils.ensureSerializable(SerializableUtils.java:81)
at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner$Evaluator.ensureSerializable(DirectPipelineRunner.java:784)
at com.google.cloud.dataflow.sdk.transforms.ParDo.evaluateHelper(ParDo.java:1025)
at com.google.cloud.dataflow.sdk.transforms.ParDo.evaluateSingleHelper(ParDo.java:963)
at com.google.cloud.dataflow.sdk.transforms.ParDo.access$000(ParDo.java:441)
at com.google.cloud.dataflow.sdk.transforms.ParDo$1.evaluate(ParDo.java:951)
at com.google.cloud.dataflow.sdk.transforms.ParDo$1.evaluate(ParDo.java:946)
at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner$Evaluator.visitTransform(DirectPipelineRunner.java:611)
at com.google.cloud.dataflow.sdk.runners.TransformTreeNode.visit(TransformTreeNode.java:200)
at com.google.cloud.dataflow.sdk.runners.TransformTreeNode.visit(TransformTreeNode.java:196)
at com.google.cloud.dataflow.sdk.runners.TransformHierarchy.visit(TransformHierarchy.java:109)
at com.google.cloud.dataflow.sdk.Pipeline.traverseTopologically(Pipeline.java:204)
at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner$Evaluator.run(DirectPipelineRunner.java:584)
at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner.run(DirectPipelineRunner.java:328)
at com.google.cloud.dataflow.sdk.runners.DirectPipelineRunner.run(DirectPipelineRunner.java:70)
at com.google.cloud.dataflow.sdk.Pipeline.run(Pipeline.java:145)
at contrail.stages.DataflowStage.stageMain(DataflowStage.java:51)
at contrail.stages.NonMRStage.execute(NonMRStage.java:130)
at contrail.stages.NonMRStage.run(NonMRStage.java:157)
at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:65)
at contrail.stages.ValidateGraphDataflow.main(ValidateGraphDataflow.java:139)
... 6 more
Caused by: java.io.NotSerializableException: org.apache.hadoop.mapred.JobConf
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1183)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1508)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1431)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1177)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
at com.google.cloud.dataflow.sdk.util.SerializableUtils.serializeToByteArray(SerializableUtils.java:47)
... 27 more
To add to what Jeremy says...
Another common cause of Serializable issues is when you use an anonymous DoFn within a non-static context. Anonymous inner classes have an implicit pointer to the enclosing class, which will cause it to get serialized as well.
If you scroll through the stack trace, one of the causes clearly identifies the data that isn't serializable.
Caused by: java.io.NotSerializableException: org.apache.hadoop.mapred.JobConf
The problem was my DoFn was taking a JobConf instance in the constructor and storing it in an instance variable. I was assuming JobConf was serializable but it turns out it isn't.
To solve this I did the following
I marked the JobConf member variable as transient so that it wouldn't be serialized.
I created a separate variable of type byte[] to store a serialized version of JobConf
In my constructor I serialized JobConf to a byte[] and stored it in an instance variable.
I overrode startBundle and deserialized the JobConf from the byte[]
Here's a gist with my DoFn.

IllegalArgument exception in custom setter after upgrading to JSF2

After upgrading to JSF2 (probably) one special accessor in an .xhtml file generates IllegalArgumentExceptions but I can't really find out why. Running the app on my local JBoss (4.2.2) does not generate this exception but this can be related to a difference between debug and live data.
Following stack trace is generated that I could extract from the production server log:
Caused by: javax.el.ELException: /xy/xy-subtemplate1.xhtml #131,45 value="#{someClass.someProperty}": java.lang.IllegalArgumentException
at com.sun.facelets.el.TagValueExpression.setValue(TagValueExpression.java:101)
at javax.faces.component.UIInput.updateModel(UIInput.java:818)
... 36 more
Caused by: java.lang.IllegalArgumentException
at sun.reflect.GeneratedMethodAccessor1134.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.el.BeanELResolver.setValue(BeanELResolver.java:108)
at com.sun.faces.el.DemuxCompositeELResolver._setValue(DemuxCompositeELResolver.java:255)
at com.sun.faces.el.DemuxCompositeELResolver.setValue(DemuxCompositeELResolver.java:281)
at org.apache.el.parser.AstValue.setValue(AstValue.java:114)
at org.apache.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:249)
at com.sun.facelets.el.TagValueExpression.setValue(TagValueExpression.java:93)
... 37 more
someClass is being iterated over in a list and has the following methods to access someProperty:
public int getSomeProperty() {
return this.getSomeRelatedEnum().ordinal();
}
public void setSomeProperty( final int index) {
this.setSomeRelatedEnum( SomeRelatedEnum.fromOrdinal( index) );
}
How can this lead to the IllegalArgumentException mentioned above?
That can happen when the setter method after all expects a different argument type than the one which is provided from EL on.
I guess that it's related to the fact that hardcoded/unconverted numbers in EL are by default treated as long and not as int. Try either changing the int to be long, or providing an explicit integer converter on the input component like so <h:someInput converter="javax.faces.Integer">.
By the way, why don't you just get/set the enum itself directly? Getting/setting the enum by its ordinal is whacky.

Changing grails "no conversion strategy" error that is not in message.properties

Is there a way to change Grails conversion mismatch error to custom message?
I am getting:
Failed to convert property value of type java.lang.String to required
type java.util.Map for property items;nested exception is
java.lang.IllegalStateException: Cannot convert value of type
[java.lang.String] to required type [java.util.Map] for property
items: no matching editors or conversion strategy found
This error type is not in messages.properties. I am getting this if a user tries to inject request parameter which is not a map into my Command Object, they shouldn't be doing this, but that besides the point:
class CartCommand implements Serializable {
Map<Integer, Integer> items =
MapUtils.lazyMap([:], FactoryUtils.constantFactory(''))
}
Thanks
Use the following key in your message.properties:
cartCommand.items.typeMismatch.map

Resources