I have a domain class that looks like this:
class Offerbyuser {
Number offerPrice
Number minHours
static constraints = {}
}
Then in a controller, I do this:
def offer = new Offerbyuser(offerPrice:1, minHours:3)
offer is always NULL. Why? Am I missing something obvious?
UPDATE: so this DOES work, but what's not working I found out is the method after that.
user.addToOutgoingOffers(offer)
user has a one-to-many relationship with Offerbyuser domain class:
class User {
static hasMany = [outgoingOffers:Offerbyuser]
}
I get this error:
groovy.lang.MissingMethodException: No signature of method: twitter4j.UserJSONImpl.addToOutgoingOffers() is applicable for argument types: (test.Offerbyuser) values: [Offer by user - Price: 1, Tweet hours: 3]
Your code works fine for me. I think that it maybe your controller class is not in the same package with your domain class, and you maynot include the domain class. Grails can not find the class you "new", but since Groovy is a dynamic language it won't throw an error.
Please try this:
In domain class
package test
class Offerbyuser {
...
}
In controller:
package test
class TestController {
...
def doSomething = {
def offer = new Offerbyuser(offerPrice:1, minHours:5)
}
}
Related
I'm defining some custom Exceptions in Dart.
I want in my logic to check the type of exception and base my processing on that, so I want to create distinct classes for each, for example like this :
class FailedToLoadCriticalDataException implements Exception { } // app cannot continue
class FailedToLoadNonCriticalDataException implements Exception { } // app can continue
However I also want to pass 2 parameters when I create these types of exceptions, the type of API call, and the API url, and the definition for that would look like this :
class UrlCallFailedException implements Exception {
String _dataTypeName;
String _urlEndpoint;
UrlCallFailedException([this._dataTypeName, this._urlEndpoint]);
#override
String toString() {
return "(${this.runtimeType.toString()}) Failed to fetch $_dataTypeName ($_urlEndpoint)";
}
}
Now what I want to do is (replace the initial definitions I made earlier and re)define my FailedToLoadCriticalDataException and FailedToLoadNonCriticalDataException classes so that they are exactly the code that is in the UrlCallFailedException class.
Is there any way to simply say something like class FailedToLoadCriticalDataException **is** UrlCallFailedException; and not need to duplicate the code that defines UrlCallFailedException ?
class FailedToLoadCriticalDataException implements UrlCallFailedException{ } is wrong because it is "Missing concrete implementations of 'getter UrlCallFailedException._dataTypeName',.."
class FailedToLoadCriticalDataException extends UrlCallFailedException{ } is wrong because when I got to throw FailedToLoadNonCriticalDataException("Foo", url); it's expectation is that there are no params ("Too many positional arguments: 0 expected, but 2 found.").
Is there a way to create multiple classes that behave exactly the same as another type and differ only in their class, without duplicating all the code ?
I've come up with this as a decent compromise :
class FailedToLoadCriticalDataException extends UrlCallFailedException {
FailedToLoadCriticalDataException([dataTypeName, urlEndpoint]) {
super._dataTypeName = dataTypeName;
super._urlEndpoint = urlEndpoint;
}
}
class FailedToLoadNonCriticalDataException extends UrlCallFailedException {
FailedToLoadNonCriticalDataException([dataTypeName, urlEndpoint]) {
super._dataTypeName = dataTypeName;
super._urlEndpoint = urlEndpoint;
}
}
Some, but minimal, code duplication, and I can now call throw FailedToLoadNonCriticalDataException("Foo", url); in my code later.
I am currently writing a wrapper around socket.io. Comming from a very object-oriented background, I want to implement the concept of Models in my framework/wrapper.
If you happen to know socket.io you might know that you get the data that is associated with an event as a parameter, now I have implemented a custom routing system where the handler of the route gets the data in an express.js like request object.
The idea is to have model classes that look something like this:
class XRequestModel
#v.String({ message: 'The username must be a string!' })
public userName: string;
}
And the route event might look something like this:
#RouteConfig({ route: '/something', model: XRequestModel })
class XEvent extends Route {
public on(req: Request<XRequestModel>, res: Response) {
// Handle Event
}
}
And to complete the example here is how the request object might look like:
class Request<T> {
public data: T;
}
Now generics in typescript are very limited since the type information is removed after compilation, I can not use the generic Request parameter ( which is the type of the model ) to get metadata from the model - Metadata, in this case, is the validation decorator. To overcome this issue I give a reference of the Model class to the RouteConfig of the RouteEvent, which is internally used and would allow me to create instances of the model, get the properties and so on...
The idea here is to give the handler of a route, a request object with pre-validated, typesafe data.
The thing holding me back from this, is the fact that unused properties, get removed after compilation by typescript, So I cannot get the metadata of the model. Initializing the class-property would solve this:
class XRequestModel
#v.String({ message: 'The username must be a string!' })
public userName: string = '';
}
But I think this makes for some very verbose syntax, and I dont want to force the user of this wrapper to init all the model properties.
An implementation side-note:
The user of the framework has to register the classes to a 'main' class and from there I can get the Route-class via decorator reflection.
When I try to get the properties of the model without initialized properties - First model example.
// Here the route.config.model refers to the model from the RouteConfig
Object.getOwnPropertyNames(new route.config.model());
>>> []
Here is what I get with initialized properties:
Object.getOwnPropertyNames(new route.config.model());
>>> [ 'userName' ]
Here a link to the GitHub repository: https://github.com/FetzenRndy/SRocket
Note that models are not implemented in this repo yet.
Basically, my question is: How can I get the properties of a class that has uninitialized properties after compilation.
The problem is that if no initialization happens, no code is emitted for the fields, so at runtime the field does not exist on the object until a value is assigned to it.
The simplest solution would be to initialize all fields even if you do so with just null :
class XRequestModel {
public userName: string = null;
public name: string = null;
}
var keys = Object.getOwnPropertyNames(new XRequestModel())
console.log(keys); // [ 'userName', 'name' ]
If this is not a workable solution for you, you can create a decorator that adds to a static field on the class and the walk up the prototype chain to get all fields:
function Prop(): PropertyDecorator {
return (target: Object, propertyKey: string): void => {
let props: string[]
if (target.hasOwnProperty("__props__")) {
props = (target as any)["__props__"];
} else {
props = (target as any)["__props__"] = [];
}
props.push(propertyKey);
};
}
class XRequestModelBase {
#Prop()
public baseName: string;
}
class XRequestModel extends XRequestModelBase {
#Prop()
public userName: string;
#Prop()
public name: string;
}
function getAllProps(cls: new (...args: any[]) => any) : string[] {
let result: string[] = [];
let prototype = cls.prototype;
while(prototype != null) {
let props: string[] = prototype["__props__"];
if(props){
result.push(...props);
}
prototype = Object.getPrototypeOf(prototype);
}
return result;
}
var keys = getAllProps(XRequestModel);
console.log(keys);
When following http://grails.org/doc/latest/guide/webServices.html#restfulControllers in order to create RESTful webservices, I am getting 404 error when I hit anything other than index.
in my Bootstrap.groovy I have
def init = { servletContext ->
new Restaurant(title:"mourne seafood").save()
new Restaurant(title:"RBG").save()
}
in my Restaurant.groovy domain class i have
class Restaurant {
String title
static constraints = {
}
}
and in my RestaurantController.groovy REST controller I have
import grails.rest.*;
class RestaurantController extends RestfulController {
static responseFormats = ['json', 'xml']
RestaurantController() {
super(Restaurant)
}
}
I thought when reading the above link that if I call
GET <domain>/restaurant
It would call the index method, which is fine, this works, however when I call
GET <domain>/restaurant/1
I thought it should call the show method with 1 as the id? However I am getting a 404. It works correctly when I hit GET <domain>/restaurant/show/2 am I wrong in thinking that when the docs say
GET /books/${id} show in the mapping table that I shouldnt have to explicitly put show in the URL?
I know It sucks but here it is:
You need to create a generic rest controller and annotate the domain class pointing to it.
First delete the RestaurantController.groovy
Then create a BaseRestController (inside the src/main/groovy folder)
src/main/groovy/BaseRestController.groovy
import grails.rest.*;
class BaseRestController<T> extends RestfulController<T> {
BaseRestController(Class<T> domainClass) {
this(domainClass, false)
}
BaseRestController(Class<T> domainClass, boolean readOnly) {
super(domainClass, readOnly)
}
#Override
def show() {
println 'showing...'
respond queryForResource(params.id)
}
}
Ps. I just override the index action to show it works
Now you can annotate the domain class
grails-app/domain/Restaurant.groovy
import grails.rest.*
#Resource(uri='/restaurants', formats=['json', 'xml'], superClass=BaseRestController)
class Restaurant {
String title
static constraints = {
}
}
You need to specify the formats in the domain class and not in the controller. Otherwise it will be ignored and XML will be default.
I named the api endpoint as restaurants instead of the grails default restaurant
Now you can HTTP your RestFull app e.g. http://localhost:8080/restaurants/1
I'm having a very simple restful controller, which looks like this:
class PersonController extends RestfulController<Person> {
static responseFormats = ['json', 'xml']
PersonController() {
super(Person)
}
}
However, now I want to add a search option to this. What is the Grails way of making this possible?
I thought of adding the following:
def search(Map params) {
println params
}
But that makes Grails (2.3) crash (| Error Fatal error during compilation org.apache.tools.ant.BuildException: Compilation Failed (Use --stacktrace to see the full trace)).
So what is the right way of adding this? I'm looking for some solution which I can call using http://localhost:8080/foo/person/search?q=erik
This is my UrlMappings:
static mappings = {
"/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
"/rest/persons"(resources:'Person')
I've changed the above to:
def search() {
println params
}
And that doesn't give the compilation error anymore, but I still get this error:
TypeMismatchException occurred when processing request: [GET] /declaratie-web/rest/medicaties/search - parameters:
q: erik
Provided id of the wrong type for class nl.Person. Expected: class java.lang.Long, got class java.lang.String. Stacktrace follows:
org.hibernate.TypeMismatchException: Provided id of the wrong type for class nl.Person. Expected: class java.lang.Long, got class java.lang.String
I also found out that it doesn't matter how I call the controller:
http://localhost:8080/foo/person/search?q=erik
http://localhost:8080/foo/person/search222?q=erik
http://localhost:8080/foo/person/search39839329?q=erik
All fails with the above error, so it seems my method is ignored (maybe caused by my URLmapping?)
You really aren't being RESTful by doing that. q should just be a parameter for the index action. You can override that method to include your functionality.
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
def c = Person.createCriteria()
def results = c.list(params) {
//Your criteria here with params.q
}
respond results, model:[personCount: results.totalCount]
}
#james-kleeh solution is right, but you can do it more clean by override the listAllResources method which is called by index
#Override
protected List<Payment> listAllResources(Map params) {
Person.createCriteria().list(params) {
// Your criteria here with params.q
}
}
I have two classes. One.groovy:
class One {
One() {}
def someMethod(String hey) {
println(hey)
}
}
And Two.groovy:
class Two {
def one
Two() {
Class groovy = ((GroovyClassLoader) this.class.classLoader).parseClass("One.groovy")
one = groovy.newInstance()
one.someMethod("Yo!")
}
}
I instantiate Two with something like this:
GroovyClassLoader gcl = new GroovyClassLoader();
Class cl = gcl.parseClass(new File("Two.groovy"));
Object instance = cl.newInstance();
But now I get groovy.lang.MissingMethodException: No signature of method: script13561062248721121730020.someMethod() is applicable for argument types: (java.lang.String) values: [Yo!]
Any ideas?
Seems like it is occurring due to the groovy class loader method being called: the string one is to parse a script in text format. Using the File one worked here:
class Two {
def one
Two() {
Class groovy = ((GroovyClassLoader) this.class.classLoader).parseClass("One.groovy")
assert groovy.superclass == Script // whoops, not what we wanted
Class groovy2 = ((GroovyClassLoader) this.class.classLoader).parseClass(new File("One.groovy"))
one = groovy2.newInstance()
assert one.class == One // now we are talking :-)
one.someMethod("Yo!") // prints fine
}
}