Inherited grails domain classes missing dynamic properties - grails

I'm having a problem where the related table id fields return 'null' from my domain objects when using inheritance. Here is an example:
In /src/groovy/
BaseClass1.groovy
class BaseClass1 {
Long id
static mapping = {
tablePerConcreteClass true
}
}
BaseClass2.groovy
class BaseClass2 extends BaseClass1 {
String someOtherProperty
static constraints = {
someOtherProperty(maxSize:200)
}
static mapping = BaseClass1.mapping
}
In /grails-app/domain
ParentClass.groovy
class ParentClass extends BaseClass2 {
ChildClass myChild
static mapping = BaseClass2.mapping << {
version false
}
}
ChildClass.groovy
class ChildClass extends BaseClass1 {
String property
static mapping = BaseClass1.mapping
}
The problem appears here:
SomeotherCode.groovy
print parentClassInstance.myChild.id // returns the value
print parentClassInstance.myChildId // returns null
Any ideas what might be going on to get those dynamic properties to break like this?

After debugging into the get(AssociationName)Id source, I found the following:
The handler for this is:
GrailsDomainConfigurationUtil.getAssociationIdentifier(Object target, String propertyName,
GrailsDomainClass referencedDomainClass) {
String getterName = GrailsClassUtils.getGetterName(propertyName);
try {
Method m = target.getClass().getMethod(getterName, EMPTY_CLASS_ARRAY);
Object value = m.invoke(target);
if (value != null && referencedDomainClass != null) {
String identifierGetter = GrailsClassUtils.getGetterName(referencedDomainClass.getIdentifier().getName());
m = value.getClass().getDeclaredMethod(identifierGetter, EMPTY_CLASS_ARRAY);
return (Serializable)m.invoke(value);
}
}
catch (NoSuchMethodException e) {
// ignore
}
catch (IllegalAccessException e) {
// ignore
}
catch (InvocationTargetException e) {
// ignore
}
return null;
}
It threw an exception on the related class (value.getClass().getDeclaredMethod), saying NoSuchMethod for the method getId(). I was unable to remove the id declaration from the base class without Grails complaining that an identifier column was required. I tried marking id as public and it also complained that it wasn't there. So, I tried this
BaseClass {
Long id
public Long getId() { return this.#id }
}
and things worked on some classes, but not on others.
When I removed the ID declaration, I go an error: "Identity property not found, but required in domain class". On a whim, I tried adding #Entity to the concrete classes and viola! everything started working.
class BaseClass {
//Don't declare id!
}
#Entity
class ParentClass {}
#Entity
class ChildClass {}
I still think it is a grails bug that it needs to be added, but at least it is easy enough to work around.

I'm not sure why you are seeing this behavior, but I'm also not sure why you are doing some of the things you are doing here. Why have a domain class extend a POGO? Domains, Controllers, and Services are heavily managed by the Grails machinery, which probably was not designed for this sort of use. Specifically, I believe Grails builds the dynamic property getters for the GrailsDomainProperty(s) of GrailsDomainClass(es), not POGO's. In this case, you have an explicitly declared id field in BaseClass1 that is not a GrailsDomainProperty. I suspect that this POGO id property is not picked up by the Grails machinery that creates the dynamic property getters for Domains.
You might try putting BaseClass1/2 in /grails-app/domain, perhaps making them abstract if you don't want them instantiated, then extending them as you are and seeing if you observe the behavior you want.

Related

Dart abstract optional parameters

How can I abstract that a methods has optional parameters?
abstract class CopyWith<T>{
T copyWith({}); // Error : Expected an identifier.
}
If I add an identifier like {test} it works and subclasses can have additional arguments
What I want to achieve?
I have a complex state manager, I make some abstraction , the following code is a minimal code, show my problem
import 'dart:collection';
abstract class CopyWith<T> {
T copyWith(OPTIONAL_NAMED_ARGUMENTS);
}
abstract class Manager<K, V extends CopyWith> {
final _map = HashMap<K, V>();
add(K key,V value){
_map[key] = value;
}
void copyWith(K key,OPTIONAL_NAMED_ARGUMENTS) {
assert(key != null);
if (_map.containsKey(key)) {
_map[key].copyWith(OPTIONAL_NAMED_ARGUMENTS);
}
}
}
class User implements CopyWith {
final int id;
final String name;
User({this.id, this.name});
User copyWith({int id, String name}) {
return User(
id: id ?? this.id,
name: name ?? this.name,
);
}
}
class UserManager extends Manager<int, User> {}
void main() {
final userManager = UserManager();
userManager.add(1,User(1,'test'));
userManager.copyWith(1,{test:'test2'})
}
As some one who has faced this issue in my library, I would say the only way is to not put a copyWith in your base class.
Why? Because you should only make a function polymorphic when there IS actually a shared calling convention and behavior. In your example, The way that these two classes perform copyWith is just different. It is, and should be, an error to send a name to Manager.copyWith, because Manager does not have a name to begin with. If you encounter a name inside a Manager.copyWith, that means there is some serious error in your code.
Also, if you actually try to invoke copyWith, as a responsible programmer, you will probably check if you are allowed to pass a name, which is,
if (someObj is User) {
someObj.copyWith(key, name: name);
} else if (someObj is Manager) {
throw IllegalStateError('You should not pass a name to a Manager! What am I supposed to do with the name now?');
}
There, you have already done type checking, so no need to make copyWith polymorphic.
However, some common behaviors can be made polymorphic, like updateKey. You can make Keyable as an interface, and Keyable updateKey(Key key) as an abstract method, and delegate to a non-polymorphic copyWith inside each subclasses.

Cannot access domain property from Java class (in src folder)

I cannot access exploits property in domain class - Scenario , from my java class - MatchScenario , located in Grails src folder.
Already tried :
Explicit methods :
I have tried explicitly creating the get;set; but I get stackOverflow error since the setExploits() is called infinitely by itself for some reason.
Service to return the exploit field,
Though the service was created, it's never called on my fork-debug integration testing, so tests hangs with no exception
compilation error ->
Error:(59, 44) java: cannot find symbol
symbol: variable exploits
location: variable scenario of type core.Scenario
Java class, error on the inner loop ->
public class MatchScenario implements Callable{
private static final Logger LOG = Logger.getLogger(MatchScenario.class.getCanonicalName());
private List<Scenario> scenarioList
#Override
public List<Scenario> call() throws Exception {
LOG.debug( "*********************** schedule matcher called *****************************" );
if (scenarioList==null) {
LOG.debug("scenarioList not initialized ");
return null;
}
List<Scenario> scenarioAvailable = new ArrayList<Scenario>();
for (Scenario scenario : scenarioList){
for (Exploit exploit : scenario.exploits){
//println 'exploit -> '+exploit
if (!match( exploit.getExpression() ) ){
break;
}
}
//happens only when all scenario are available ( no break issued )
scenarioAvailable.add(scenario);
}
return scenarioAvailable;
}
private boolean match(String expression) {
return true;
}
}
Scenario domain object ->
package core
class Scenario {
String name
static belongsTo = [ Exploit ]
static hasMany = [ exploits : Exploit ]
static constraints = {
name nullable: false , maxSize: 32
}
}
You're confusing fields and properties. When you declare a property in a Groovy class, e.g. String name, the Groovy compiler converts that to a private field and adds a getter and a setter (unless you already defined one or both of them - it won't overwrite), in this case something like
private String name
public void setName(String name) { this.name = name }
public String getName() { return name }
It only does this if there's no scope modifier, so public String name and protected String name would both stay as defined.
One benefit of this is that you can later add logic to the getter and/or setter to modify the value, do some validation checks or computations, etc., and in Groovy you would still read and write to the name property since property access always calls the underlying setters and getters, and since properties like this are a Groovy-only thing that Java can't access, you would have been calling the setter and getter from Java all along, so you wouldn't need to recompile the Java classes that used the class.
Declaring a hasMany like yours creates an exploits property, effectively
Set<Exploit> exploits
and that property (added by a Grails AST transformation) is likewise converted to a private field with a getter and setter. So to get this working from Java, use the getter:
for (Exploit exploit : scenario.getExploits()) {

Accessing static variable through subclass method

I'm get null returned when attempting to access a subclass static variable through a overridden subclass accessor:
library resource;
abstract class Resource
{
String name;
String description;
Resource(this.name, this.description);
Resource.map(Map data)
{
...
_getDb()[this] = data;
}
abstract Map _getDb();
}
class Skill extends Resource
{
static Map _skills = {}
Skill.map(Map data) : super.map(data);
Map_getDb()
{
return _skills;
}
}
import 'resource.dart'
void main() {
useVMConfiguration();
test('constructor', () {
Skill skill = new Skill.map({
'name': 'foo'
});
}
}
Here I'm trying to call _getDb() on the (hopefully) now constructed subclass in the super constructor. Despite _skills being instantiated, _getDb() returns null.
Is this possible?
EDIT:
_skills is not present when inspecting this at _getDb():
this Skill [id=0]
description "bar" [id=19]
name "foo" [id=18]
Your example has several flaws as DartEditor shows.
Map_getDb() is missing a space between Map and _getDb().
Is this only in your question or in the code you run too?
abstract Map _getDb(); is also a syntax error.
In Dart a method is made abstract when you don't provide an implementation (; instead of {})
After this fixes the code works fine.

How do I fake a validation error?

I'm using the Grails Webflow plugin. Here are the domain objects I'm working with:
class Foo implements Serializable {
String fooProp1,
fooProp2
static constraints = {
fooProp2 nullable: false
}
}
class Bar implements Serializable {
Foo fooObject
static constraints = {
fooObject nullable: false
}
}
At a point in the webflow, I need to make sure that fooObject.fooProp1 is not null. If it is, I want to throw an error and force the user to supply it with a value. I tried using validate() to do this (on both the Bar and Foo objects), but since fooProp1 has the nullable:true property, it passes validation. Any ideas?
You can probably do this in the Web Flow by adapting the following code:
if(fooObject.fooProp1 == null) {
fooObject.errors.rejectValue('fooProp1', 'nullable')
}
The second argument to that method, 'nullable', might be different for your situation. You'll just need to set it to the message code (from message.properties) to display the error message that you want.
Have a look here for more ways to use reject() and rejectValue().

Set Inner Dependency by Type using Structuremap

I have a structuremap configuration that has me scratching my head. I have a concrete class that requires a interfaced ui element which requires an interfaced validation class. I want the outer concrete class to get the default ui element, but get a concrete-class-specific validation object. Something like this:
class MyView
{
IPrompt prompt
}
class GenericPrompt : IPrompt
{
IValidator validator
}
class MyValidator : IValidator
{
bool Validate() {}
}
How can I configure structuremap with the Registry DSL to only use MyValidator when creating dependencies for MyView. (And assumedly using BobsValidator when creating dependencies for BobsView)
Are you getting MyView (and BobsView) from the container? Can we assume that they will all take an instance of IPrompt?
One approach would be to register all of your validators with a name that matches the names of your view. You could implement your own type scanner that just removes the Validator suffix:
public class ValidatorScanner : ITypeScanner
{
public void Process(Type type, PluginGraph graph)
{
if (!typeof (IValidator).IsAssignableFrom(type)) return;
var validatorName = type.Name.Replace("Validator", "");
graph.AddType(typeof(IValidator), type, validatorName);
}
}
Now, if you assume an IPrompt will always be requested by a View that follows that naming convention, your registry could look like:
public class ValidatorRegistry : Registry
{
public ValidatorRegistry()
{
Scan(scan =>
{
scan.TheCallingAssembly();
scan.With<ValidatorScanner>();
});
ForRequestedType<IPrompt>().TheDefault.Is.ConstructedBy(ctx =>
{
var viewName = ctx.Root.RequestedType.Name.Replace("View", "");
ctx.RegisterDefault(typeof(IValidator), ctx.GetInstance<IValidator>(viewName));
return ctx.GetInstance<GenericPrompt>();
});
}
}
To retrieve your view with the appropriate validator, you would have to request the concrete type:
var view = container.GetInstance<MyView>();
Note that this will only work if you are retrieving your view with a direct call to the container (service location), since it depends on the "Root.RequestedType". Depending on how you plan to get your views, you might be able to walk up the BuildStack looking for a View (instead of assuming it is always Root).

Resources