Grails gorm findBy* with interface properties - grails

I do find a related question with this and I exactly have the same problem. link : Grails FindBy* with an inteface property
Yes, we can't change the Interface property to an abstract property.
I've read that findBy* can't handle interface property but any graceful tips on how we can proceed on this?
As for the models:
interface InterfaceClass {
//method
}
class EnumClass implements InterfaceClass {
//implementation of method
}
class NonEnumDomain {
InterfaceClass interfaceClass
}
Going back to the issue, also regarding the sited link regarding findBy limitations.
NonEnumDomain.findByInterfaceClass(....) won't work.
In case it's needed for the community to know: we did some UserType on these interface properties since it's an Enum properties.
Thanks

Here I'm assuming that you have the full control over the InterfaceClass and for the desired property it has getter and setter methods declared.
So let's say you would like to have two properties named: name and description in your interface class. Create the getter and setter method declaration there and don't declare the properties there.
interface InterfaceClass {
String getName()
String getDescription()
void setName(String name)
void setDescription(String description)
}
EnumClass class would contain those properties and will implement the InterfaceClass.
class EnumClass implements InterfaceClass {
String name
String description
String getName() {
return name
}
void setiName(String name) {
this.name = name
}
String getDescription() {
return description
}
void setDescription(String description) {
this.description = description
}
}
Now to make the finder methods work for your InterfaceClass, you just have to add the interfaceClass property in your domain class to embedded properties list.
class NonEnumDomain {
InterfaceClass interfaceClass
static embedded = ['interfaceClass']
}
To save the instance of NonEnumDomain:
new NonEnumDomain(interfaceClass: new EnumClass(name: "Sandeep Poonia", description: "Interface property in domain class")).save(failOnError: true, flush: true)
and to find an instance using finders:
NonEnumDomain.findByInterfaceClass(new EnumClass(name: "Sandeep Poonia", description: "Interface property in domain class"))
Definition of embedded keyword:
Supports embedding domain components into domain classes. An embedded
component does not store its data in its own table as a regular domain
class relationship does. Instead, the data is included in the owner's
table. The embedded component class is typically declared in the same
source file as the owning class or in its own file under src/groovy.
Constraints can also be applied over properties of embedded components
using Validateable annotation.

Related

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()) {

java.lang.IllegalAccessException: can not access a member of class java.util.Collections$UnmodifiableCollection with modifiers "public"

I have classes PrimitiveProperty and ComplexProperty and the interface Property. I want to create an implementation of Property which enforces an empty unmodifiable Set of Property instances as return value of Property.getProperties, e.g.
public interface Property {
Set<Property> getProperties();
}
public class ComplexProperty implements Property {
private Set<Property> properties;
//getter overrides the interface method
}
public class PrimitiveProperty implements Property {
private final static Set<Property> EMPTY_PROPS = Collections.unmodifiableSet(new HashSet<Property>(1));
#Override
public Set<Property> getProperties() {
return EMPTY_PROPS;
}
}
With Glassfish 4.0 and I'm getting
java.lang.IllegalAccessException: Class javax.el.ELUtil can not access a member of class java.util.Collections$UnmodifiableCollection with modifiers "public"
when I access the property in the leaf attribute of a Richfaces tree, e.g.
<r:tree id="aTree"
toggleType="ajax" var="item" >
<r:treeModelRecursiveAdaptor roots="#{aCtrl.roots}"
nodes="#{item.properties}" leaf="#{item.properties.isEmpty()}">
<r:treeNode>
#{item.name}
</r:treeNode>
<r:treeModelAdaptor nodes="#{item.properties}" leaf="#{item.properties.isEmpty()}"/>
</r:treeModelRecursiveAdaptor>
</r:tree>
The issue disappears if I make the EMPTY_PROPS constant modifiable (by assigning an instance of HashSet instead of the return value of Collections.unmodifiableSet) which is not my intention.
Is it possible to achieve what I want to do? Do I have to invent or use an implementation of what Collections$UnmodifiableCollection ('s subclasses) do(es) which is compatible with the JSF access needs?
Here is the problem:
leaf="#{item.properties.isEmpty()}"
You're attempting to invoke a method directly on the UnmodifiableSet instance. Although it implements Collection, which is public, the UnmodifiableSet implementation itself, where EL (read: Reflection API) is trying to find the method on the class, is not public.
Exactly this problem is reproducible in plain Java (a main() method) as follows:
Set<Object> set = Collections.unmodifiableSet(new HashSet<>());
for (Method method : set.getClass().getMethods()) {
if ("isEmpty".equals(method.getName())) {
method.invoke(set); // IllegalAccessException.
}
}
This is essentially a bug in the EL implementation used.
You'd better just use EL's own empty operator:
leaf="#{empty item.properties}"

Inherited grails domain classes missing dynamic properties

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.

Doing interception with structuremap

I'm trying to do some attribute-based interception using structuremap but I'm struggling to tie up the last loose ends.
I have a custom Registry that scans my assemblies and in this Registry I have defined the following ITypeInterceptor whose purpose it is to match types decorated with the given attribute and then apply the interceptor if matched. The class is defined as such:
public class AttributeMatchTypeInterceptor<TAttribute, TInterceptor>
: TypeInterceptor
where TAttribute : Attribute
where TInterceptor : IInterceptor
{
private readonly ProxyGenerator m_proxyGeneration = new ProxyGenerator();
public object Process(object target, IContext context)
{
return m_proxyGeneration.CreateInterfaceProxyWithTarget(target, ObjectFactory.GetInstance<TInterceptor>());
}
public bool MatchesType(Type type)
{
return type.GetCustomAttributes(typeof (TAttribute), true).Length > 0;
}
}
//Usage
[Transactional]
public class OrderProcessor : IOrderProcessor{
}
...
public class MyRegistry : Registry{
public MyRegistry()
{
RegisterInterceptor(
new AttributeMatchTypeInterceptor<TransactionalAttribute, TransactionInterceptor>());
...
}
}
I'm using DynamicProxy from the Castle.Core to create the interceptors, but my problem is that the object returned from the CreateInterfaceProxyWithTarget(...) call does not implement the interface that triggered the creation of the target instance in structuremap (i.e IOrderProcessor in example above). I was hoping that the IContext parameter would reveal this interface, but I can only seem to get a hold of the concrete type (i.e. OrderProcessor in example above).
I'm looking for guidance on how to have this scenario work, either by calling the ProxyGenerator to return an instance that implements all interfaces as the target instance, by obtaining the requested interface from structuremap or through some other mechanism.
I actually got something working with a slight caveat so I'll just post this as the answer. The trick was to obtain the interface and pass that into the CreateInterfaceProxyWithTarget. My only problem was that I could not find a way to query the IContext about which interface it was currently resolving so I ended up just looking up the first interface on the target which worked for me. See code below
public class AttributeMatchTypeInterceptor<TAttribute, TInterceptor> :
TypeInterceptor
where TAttribute : Attribute
where TInterceptor : IInterceptor
{
private readonly ProxyGenerator m_proxyGeneration = new ProxyGenerator();
public object Process(object target, IContext context)
{
//NOTE: can't query IContext for actual interface
Type interfaceType = target.GetType().GetInterfaces().First();
return m_proxyGeneration.CreateInterfaceProxyWithTarget(
interfaceType,
target,
ObjectFactory.GetInstance<TInterceptor>());
}
public bool MatchesType(Type type)
{
return type.GetCustomAttributes(typeof (TAttribute), true).Length > 0;
}
}
Hope this helps someone

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