I've got grails domain class that looks like this
class Thing {
String name
static hasMany = [
variants: Variant
]
}
and another one like this
class Variant {
String name
static belongsTo = [
thing: Thing
]
}
I'm trying to get the hal renderer to do a deep rendering.
Is that possible? How should I achieve it?
Same problem here, it seems a known bug in grails (https://jira.grails.org/browse/GRAILS-10954)
There is a (not very nice) workaround,
#Transactional(readOnly = true)
class ProductController extends RestfulController {
def halPCollectionRenderer
def halPRenderer
static responseFormats = ['hal','json']
ProductController() {
super(Product)
}
#PostConstruct
void init() {
halPCollectionRenderer.mappingContext = mappingContext
halPRenderer.mappingContext = mappingContext
}
MappingContext getMappingContext() {
final context = new KeyValueMappingContext("")
context.addPersistentEntity(Product)
context.addPersistentEntity(Category)
return context
}
}
Hope it helps.
Related
I have a problem with data binding and dirty properties.
There are two simple domains
class Parent {
String name
static hasMany = [children: Child]
}
class Child {
String name
static belongsTo = [parent: Parent]
}
I created a simple rest controller to check all options
class TestController {
static responseFormats = ['json']
#Transactional
def add() {
def parent = new Parent(name: params.name).save()
respond(parent)
}
#Transactional
def parents() {
def parents = Parent.findAll()
respond(parents)
}
#Transactional
def testWithCommand(ParentCmd cmd) {
Parent parent = Parent.findById(cmd.id)
bindData(parent, cmd)
parent.save()
respond(parent)
}
#Transactional
def testWithParams() {
Parent parent = Parent.findById(params.id)
bindData(parent, params)
parent.save()
respond(parent)
}
#Transactional
def testWithRelation(ParentCmd cmd) {
Parent tempParent = new Parent()
bindData(tempParent, cmd)
Parent parent = Parent.findById(cmd.id)
for (Child child : tempParent.children) {
parent.addToChildren(child)
}
parent.save()
respond(parent)
}
}
so we have 3 update options: cmd with binding, params with binding and cmd with addTo*
I created simple event to catch dirty properties
class TestEventListener extends AbstractPersistenceEventListener {
protected TestEventListener(Datastore datastore) {
super(datastore)
}
#Override
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
if (event.entityObject instanceof Parent) {
List<String> dirtyProperties = new ArrayList<String>(((DirtyCheckable) event.entityObject).listDirtyPropertyNames())
println("DIRTY PROPERTIES: " + dirtyProperties.size())
println(dirtyProperties.join(", "))
}
}
#Override
boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
eventType == PreUpdateEvent.class
}
}
Then I used Postman, I created one record and updated it in each of three ways.
In two cases there was no dirty properties.
Only when I used addToChildren() I saw children in dirty properties.
Does anyone have any knowledge about this?
Did you have problems with binding? Is it normal or did I miss something?
I will be grateful for every answer.
Thx,
A.
Is there a way to utilize bindData in a service other than using the deprecated BindDynamicMethod? I can't just use
TestObject testObject = new TestObject()
TestObject testObject.properties = params
or
TestObject testObject = new TestObject(params)
because I have a custom bind method utilizing the #BindUsing annotation within my TestObject class.
If you are using Grails 3.* then the service class can implement DataBinder trait and implement bindData() as shown below example:
import grails.web.databinding.DataBinder
class SampleService implements DataBinder {
def serviceMethod(params) {
Test test = new Test()
bindData(test, params)
test
}
class Test {
String name
Integer age
}
}
This is how I quickly tried that in grails console:
grailsApplication.mainContext.getBean('sampleService').serviceMethod(name: 'abc', age: 10)
In Grails 2.4.4 you can do something like this:
// grails-app/services/demo/HelperService.groovy
package demo
import org.grails.databinding.SimpleMapDataBindingSource
class HelperService {
def grailsWebDataBinder
TestObject getNewTestObject(Map args) {
def obj = new TestObject()
grailsWebDataBinder.bind obj, args as SimpleMapDataBindingSource
obj
}
}
In 2.5, I found that emulating the behaviour of the Controller API in a helper service worked:
def bindData(def domainClass, def bindingSource, String filter) {
return bindData(domainClass, bindingSource, Collections.EMPTY_MAP, filter)
}
def bindData(def domainClass, def bindingSource, Map includeExclude, String filter) {
DataBindingUtils
.bindObjectToInstance(
domainClass,
bindingSource,
convertToListIfString(includeExclude.get('include')),
convertToListIfString(includeExclude.get('exclude')),
filter);
return domainClass;
}
convertToListIfString is as per the controller method:
#SuppressWarnings("unchecked")
private List convertToListIfString(Object o) {
if (o instanceof CharSequence) {
List list = new ArrayList();
list.add(o instanceof String ? o : o.toString());
o = list;
}
return (List) o;
}
At the moment I have a Base class that contains a member I would like to inject. However, I would like the concrete type of this member to depend on the Subclass being instantiated. What I am aiming for is something along these lines:
public interface StringInterface {
public String getString();
}
public class HelloStringConcrete implements StringInterface {
public String getString() {
return "Hello";
}
}
public class WorldStringConcrete implements StringInterface {
public String getString() {
return "World";
}
}
public abstract class Base {
#Inject StringInterface member;
public Base() {
// Assume access to object graph
MyObjectGraph.get().inject(this);
}
public void printSomething() {
System.out.println(member.getString());
}
}
public class SubclassHello extends Base {}
public class SubclassWorld extends Base {}
#Module(injects = {SubclassHello.class})
public class HelloModule {
#Provides StringInterface provideStringInterface() {
return new HelloStringConcrete();
}
}
#Module(injects = {SubclassWorld.class})
public class WorldModule {
#Provides StringInterface provideStringInterface() {
return new WorldStringConcrete();
}
}
So now what I would like to do is something along the lines of:
#Module(
includes = {
HelloModule.class,
WorldModule.class
}
)
public class BigModule {}
// Somewhere in another piece of code...
objectGraph = ObjectGraph.create(new BigModule());
// In yet another piece of code...
SubclassHello hello = new SubclassHello();
SubclassWorld world = new SubclassWorld();
hello.printSomething();
world.printSomething();
// Hopefully would result in :
// Hello
// World
This type of setup won't work though, because including two modules with the same provider will result in a duplicate provider error at compile time. It would be cool to see a solution to this problem without introducing #Named or #Qualifer annotations, or using scoped graph extensions via graph.plus() because these strategies necessarily introduce coupling to the subclasses
This is possible but I think the code I've attached below is more coupled than using scoped graphs or annotations. Basically you can use constructor injection to inject concrete dependencies to your
SubclassHello and SubclassWorld.
public abstract class Base {
private final StringInterface member;
public Base(StringInterface member) {
this.member = member;
}
...
}
#Module(injects = {SubclassWorld.class})
public class WorldModule {
#Provides
WorldStringConcrete provideStringInterface() {
return new WorldStringConcrete();
}
}
public class SubclassWorld extends Base {
#Inject
public SubclassWorld(WorldStringConcrete worldStringConcrete) {
super(worldStringConcrete);
}
}
#Module(injects = {SubclassHello.class})
public class HelloModule {
#Provides
HelloStringConcrete provideStringInterface() {
return new HelloStringConcrete();
}
}
public class SubclassHello extends Base {
#Inject
public SubclassHello(HelloStringConcrete helloStringConcrete) {
super(helloStringConcrete);
}
}
// Somewhere in another piece of code...
ObjectGraph objectGraph = ObjectGraph.create(new BigModule());
// In yet another piece of code...
SubclassHello hello = objectGraph.get(SubclassHello.class);
SubclassWorld world = objectGraph.get(SubclassWorld.class);
I don't think there are other solutions. How could Dagger find out which StringInterface implementations should be injected to the concrete classes?
I'm trying to do the following in Grails:
class I18nEnum implements MessageSourceResolvable {
public Object[] getArguments() { [] as Object[] }
public String[] getCodes() { [ this.class.canonicalName+'.'+name() ] }
public String getDefaultMessage() { "?-" + name() }
}
and then use this class like this:
class MyDomainClass {
#Mixin(I18nEnum)
public static enum MaritalStatus {
SINGLE, MARRIED
}
MaritalStatus maritalStatus
}
Then MyDomainClass is used with scaffolding to generate an HTML select field, and to have the options translatable in messages.properties like this:
my.package.MyDomainClass.MaritalStatus.SINGLE = Single
my.package.MyDomainClass.MaritalStatus.MARRIED = Married
But I cannot find a way to get the name of the target class (my.package.MyDomainClass.MaritalStatus), and instead I get the name of the mixin class (my.package.I18nEnum#1dd658e9)
How can I get the target class of a groovy mixin?
Is there a way to do something like this?
public String[] getCodes() { [ this.targetClass.canonicalName+'.'+name() ] }
Or like this?
public String[] getCodes() { [ this.mixinTargetClass.canonicalName+'.'+name() ] }
Note: For the moment the only way that I made this enum internationalization feature to work was by just copy-pasting this for every enum class defined in the application:
public static enum MaritalStatus implements MessageSourceResolvable {
SINGLE, MARRIED
public Object[] getArguments() { [] as Object[] }
public String[] getCodes() { [ this.class.canonicalName+'.'+name() ] }
public String getDefaultMessage() { name() }
}
MaritalStatus maritalStatus
But I would like to not repeat the same code for every enum, but instead just mixin the required methods implementing MessageSourceResolvable.
Mixins do not work with enums. May be it will be useful for you:
class Mix {
def enumClazz
Mix(def clz) { enumClazz = clz }
def getCode() { println "---> ${enumClazz.name()}"}
}
enum MaritalStatus {
SINGLE, MARRIED
#Delegate Mix mixClz = new Mix(this)
}
MaritalStatus.MARRIED.code
Consider the following class
public class SchemaExecutor: ISchemaExecutor
{
public SchemaExecutor(SqlPlusSettings sqlPlusSettings)
{
_sqlPlusSettings = sqlPlusSettings;
}
...
And container configuration
ObjectFactory.Initialize( x =>
{
SqlPlusSettings sqlPlusSettings = GetSqlPlusSettings();
x.ForRequestedType<ISchemaExecutor>().TheDefaultIsConcreteType<SchemaExecutor>()
.WithCtorArg("sqlPlusSettings").EqualT(sqlPlusSettings);
});
But .WithCtorArg works only for primitives and so the initialization above doesn't work.
Is there any way to configure constructor with non primitive parameter?
You need to just let the IoC do what it does and inject your dependencies for you...
ObjectFactory.Initialize( x =>
{
x.ForRequestedType<SqlPlusSettings>().TheDefaultIsConcreteType<SqlPlusSettings>().AsSingletons;
x.ForRequestedType<ISchemaExecutor>().TheDefaultIsConcreteType<SchemaExecutor>();
});
SqlPlusSettings sqlPlusSettings = GetSqlPlusSettings();
ObjectFactory.Inject<SqlPlusSettings>(sqlPlusSettings);
The way you have it here with none of the AutoWiring, I think the redundant line for SqlPlusSettings is needed to let StructureMap know about it. But essentially SM knows about both the SchemaExecutor and the SqlPlusSettings and when instantiating the SchemaExecutor it looks for the parameters, see's that the SqlPlusSettings is a singleton and it already has one and passes it to instantiate the SchemaExecutor.
If you wish to control exactly what instance of the settings object your class will receive you can accomplish this by either configuring the concrete class or per plugin by configuring its dependency.
Note: I am using the trunk but I believe that everything here is available in 2.5.3.
public class MySettings
{
}
public interface IMyClass
{
MySettings Settings { get; }
}
public class MyClass : IMyClass
{
public MySettings Settings { get; private set; }
public MyClass(MySettings settings)
{
Settings = settings;
}
}
[TestFixture]
public class registry_test
{
[Test]
public void configure_concrete_class()
{
var mySettings = new MySettings();
var container = new Container(config =>
{
config.For<MySettings>().Use(mySettings);
config.For<IMyClass>().TheDefaultIsConcreteType<MyClass>();
});
container.GetInstance<IMyClass>().Settings.ShouldBeTheSameAs(mySettings);
}
[Test]
public void configure_concrete_ctor_dependency()
{
var mySettings = new MySettings();
var container = new Container(config =>
{
config.For<IMyClass>().TheDefault.Is.OfConcreteType<MyClass>()
.CtorDependency<MySettings>().Is(mySettings);
});
container.GetInstance<IMyClass>().Settings.ShouldBeTheSameAs(mySettings);
}
}