I just implemented a dynamic dropdown menu based on https://stackoverflow.com/a/3771240/3691484, but now whenever I try to create an object based on the 2nd dropdown list, I get
|
java.lang.NoSuchMethodException: java.util.Set.<init>()
Error |
at java.lang.Class.getConstructor0(Class.java:2810)
Error |
at java.lang.Class.getDeclaredConstructor(Class.java:2053),
basically the same error as https://jira.grails.org/browse/GRAILS-10635. However, the solution listed in the JIRA doesn't seem to applicable to my case, as this is how my domain class is (Tag is the primary select box, subtag dynamically changes based on the tag selected)
class Tag {
static scaffolding = true
String template
String tagName
static hasMany = [subtags: Subtag]
String toString()
{
"${tagName} - ${template}"
}
static constraints = {
template(inList: ["Proposal", "Resume", "Training Manual"])
}
}
Any ideas?
I think this is fixed in recent versions of Grails. If you can still produce it with the latest 2.3.x release, please file a JIRA, but I don't think this is still a problem.
Related
I'm using the web-micro profile from Grails 3.x to write microservices. I need to be able to search on one of the fields. I believe in previous versions of grails, you could add the fields to the query string.
http://localhost:3141/zipcode?zip=55509 would return just the zipcode object(s) that had that value for zip.
This does not seem to work in Grails 3.x web-micro.
#Entity
#Resource(uri="/zipcode")
class ZipCode {
static belongsTo = [kingdomGroup : KingdomGroup]
String zip
static constraints = {
}
String toString() { zip }
}
Confirm that kingdomGroup is initialized properly?
secondly, confirm the datasource that you're using, and that it has data as expected.
So I decided to use AjaxDependencySelection Plugin for Grails, and it has proven to be very useful. However, I am trying to implement autoComplete boxes, and it does not seem to be saving the object id when using an Autocompleted selection. Here is my implementation in my gsp
<g:selectPrimary id="template" name="template"
domain='dms.nexusglobal.Template'
searchField='templateName'
collectField='id'
domain2='dms.nexusglobal.Tag'
bindid="template.id"
searchField2='tagName'
collectField2='id'
hidden="hiddenNew"
noSelection="['': 'Please choose Template']"
setId="tag"
value="${documentPartInstance?.template}"/>
<g:selectSecondary id="tag" name="tag"
domain2='dms.nexusglobal.Subtag'
bindid="tag.id"
searchField2='subtagName'
collectField2='id'
autocomp="1"
noSelection="['': 'Please choose Tag']"
setId="subtag"
value="${documentPartInstance?.tag}"/>
<g:autoCompleteSecondary id="subtag" name="subtagId"
domain='dms.nexusglobal.Subtag'
primarybind='tag.id'
hidden='tag'
hidden2='hidden5'
searchField='subtagName'
collectField='id'
value='${documentPartInstance?.subtag}'/>
<input type=hidden id="hidden5" name="subtagId" value="${documentPartInstance?.subtag}"/>
However, everytime I save it, I am presented with this error Column 'subtag_id' cannot be null . Here is my domain class definition for Subtag
class Subtag {
static scaffold = true
String subtagName
static belongsTo = [tag : Tag]
public Subtag()
{
}
public Subtag(String s)
{
subtagName = s
}
static constraints = {
}
String toString(){
subtagName
}
}
Tag hasMany subtags as well
It seems to be creating new Subtag instances when using the autoselect box (as an error shows up saying Could not find matching constructor for:packagename.Subtag(java.lang.String) Although this is a feature I am looking to implement in my application at later stages (being able to create new Subtags on the fly when creating a document Part), right now, all I would like to be able to do is just choose from my already existing subtags.
When I add in a string constructor, it comes back with the error that Column subtag_id cannot be null
I have developed it so will try help you through your issue.
The problem is that you are trying to push a value from selectSecondary and update the elementId of g:autocomplete which is actually a seperate entity.
I will update the plugin with a new method, need to test it out first.. Also take a look at g:selectAutoComplete. Although this method would only work if your secondary was the primary task... so no good in that case either..
hang on and look out for 0.37 release
Released 0.37 documentation on how to do such a thing here: https://github.com/vahidhedayati/ajaxdependancyselection/wiki/from-selection-to-autocomplete---how-to
I was under the wrong impression of saving enum type as ordinal values after completion of the issue https://jira.grails.org/browse/GPMONGODB-232 that we can now save enum with the custom id.
For example:
This won't save field type with values either 2 or 3.
package test
class User {
static mapping = {
//type enumType: "ordinal"
}
UserType type
String name
}
enum UserType {
A(2),
B(3),
int getId() {
this.id
}
final int id
UserType(int id) {
this.id = id
}
}
How can we save enum with custom ids (as shown above) in a grails app with mongodb plugin installed?
I haven't checked Grails 2.4 yet, but in 2.3.8 (or at least in grails-datastore-core 3.1.0) you can't.
The issue that you referenced referred to the using built-in ordinal value of the Enum class, not a property value. What you want is a custom type marshaller (or perhaps the subclass AbstractMappingAwareCustomTypeMarshaller). Unfortunately, Grails checks to see if a property is an enum before considering a custom type mapper. From org.grails.datastore.mapping.model.config.GormMappingConfigurationStrategy#getPersistentProperties():
else if (Enum.class.isAssignableFrom(currentPropType) ||
propertyFactory.isSimpleType(propertyType)) {
persistentProperties.add(propertyFactory.createSimple(entity, context, descriptor));
}
else if (MappingFactory.isCustomType(propertyType)) {
persistentProperties.add(propertyFactory.createCustom(entity, context, descriptor));
}
I'd say that this is a bug and if it is still present in 2.4.4 (or whatever the latest version currently is) then it should be reported to Grails.
Answering my own question in case anyone need this feature. Now mongodb also supports saving enum with custom id as explained in the question.
The changes required are already merged by pull request https://github.com/grails/grails-data-mapping/pull/41 and they just have to release a new version of mongodb or GORM.
All of this is on Grails 2.2.3.
I have two classes in a One-to-many relationship, and a service which removes a list of ids
class Box {
String name
static hasMany = [items:ItemDomain]
static constraints = {
items(nullable:true)
}
}
and
class ItemDomain { String name Box box
static belongsTo = Box
static constraints = {
name(blank:false,unique:['box'], maxSize:127)
box(nullable:false) } }
In the service, here's the problem section:
def itemsToDelete = params.itemsToDelete //List of DB ids
List<ItemDomain> items= []
items.addAll(box.items) //Copy the list to avoid concurrent mod exception
for(ItemDomain item : items)
{
if(itemsToDelete.contains(item.id))
{
box.removeFromItems(item)
item.delete()
}
box.save(flush: true)
}
This works fine when running the application, but from integration testing it fails with
InvalidDataAccessApiUsageException: deleted object would be re-saved by cascade (remove deleted object from associations)
If I take out the flush, and eventually it will fail with:
Field error in object 'mypackage.ItemDomain' on field 'box': rejected value [null];
Adding logging, I see the size of box.items before entering the loop is the same as it is after exiting the loop, printing the items in the loop before and after shows that the item.box field for the deleted items changes to null. I've tried messing with the cascade mapping in the parent class... I'm at a loss as to whether I'm doing something wrong or if this is an issue with integration testing. The only similar issues I found were against grails 1.1 and had no resolution in the threads that I found.
I appreciate any feedback.
So, not surprisingly, I was doing something wrong. It turns out that my equals() and hashCode() implementations on the ItemDomain class were including a field that was never supposed to change, but due to requirements creep, was now changing and the methods never got updated properly.
I tried to change the standard 'id' in grails:
calls Book {
String id
String title
static mapping {
id generator:'assigned'
}
}
unfortunately, I soon noticed that this breaks my bootstrap. Instead of
new Book (id:'some ISBN', title:'great book').save(flush:true, failOnError:true)
I had to use
def b = new Book(title:'great book')
b.id = 'some ISBN'
b.save(flush:true, failOnError:true)
otherwise I get an 'ids for this class must be manually assigned before calling save()' error.
but that's ok so far.
I then encountered the same problem in the save action of my bookController. But this time, the workaround didn't do the trick.
Any suggestions?
I known, I can rename the id, but then I will have to change all scaffolded views...
That's a feature of databinding. You don't want submitted data to be able to change managed fields like id and version, so the Map constructor that you're using binds all available properties except those two (it also ignores any value for class, metaClass, and a few others).
So there's a bit of a mismatch here since the value isn't managed by Hibernate/GORM but by you. As you saw the workaround is that you need to create the object in two steps instead of just one.
I can't replicate this problem (used Grails 2.0.RC1). I think it might be as simple as a missing equal sign on your static mapping = { (you just have static mapping {)
Here's the code for a domain object:
class Book {
String id
String name
static mapping = {
id generator:'assigned'
}
}
And inside BootStrap.groovy:
def init = { servletContext ->
new Book(name:"test",id:"123abc").save(failOnError:true)
}
And it works fine for me. I see the id as 123abc.
You need to set the bindable constraint to true for your id prop, e.g.
class Employee {
Long id
String name
static constraints = {
id bindable: true
}
}