I generated controller under rest-api grails app profile. Nothing is changed in controller, just some println calls added.
For call curl -X PUT -d name=petr2 -d phone=338 localhost:8080/TSCell/3 I have {"message":"Internal server error","error":500} response. In debug I can see, that error occured after final respond TSCell, [status: OK, view:"show"] call.
Code for update method:
#Transactional
def update(TSCell tSCell) {
println "in update method"
if (tSCell == null) {
transactionStatus.setRollbackOnly()
render status: NOT_FOUND
return
}
if (tSCell.hasErrors()) {
transactionStatus.setRollbackOnly()
respond tSCell.errors, view:'edit'
return
}
tSCell.save flush:true
respond tSCell, [status: OK, view:"show"]
}
And stack trace
ERROR org.grails.web.errors.GrailsExceptionResolver - IllegalArgumentException occurred when processing request: [PUT] /TSCell/3
Model variable [TSCell] of with value [class zcrm.api.TSCell] type [java.lang.Class] is not of the correct type [zcrm.api.TSCell]. Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:210)
at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:187)
at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doPut(FrameworkServlet.java:883)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Caused by: grails.views.ViewRenderException: Error rendering view: Model variable [TSCell] of with value [class zcrm.api.TSCell] type [java.lang.Class] is not of the correct type [zcrm.api.TSCell]
at grails.views.AbstractWritableScript.writeTo(AbstractWritableScript.groovy:33)
at grails.views.mvc.GenericGroovyTemplateView.renderMergedOutputModel(GenericGroovyTemplateView.groovy:71)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:303)
at grails.views.mvc.renderer.DefaultViewRenderer.render(DefaultViewRenderer.groovy:105)
at grails.artefact.controller.RestResponder$Trait$Helper.internalRespond(RestResponder.groovy:188)
at grails.artefact.controller.RestResponder$Trait$Helper.respond(RestResponder.groovy:98)
at zcrm.api.TSCellController$$EQ0icN2W.$tt__update(TSCellController.groovy:64)
at grails.transaction.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:96)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:93)
at grails.transaction.GrailsTransactionTemplate$2.doInTransaction(GrailsTransactionTemplate.groovy:96)
at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
at grails.transaction.GrailsTransactionTemplate.execute(GrailsTransactionTemplate.groovy:93)
... 14 common frames omitted
Caused by: java.lang.IllegalArgumentException: Model variable [TSCell] of with value [class zcrm.api.TSCell] type [java.lang.Class] is not of the correct type [zcrm.api.TSCell]
at grails.views.WritableScriptTemplate.make(WritableScriptTemplate.groovy:138)
at grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper.prepareWritable(DefaultGrailsJsonViewHelper.groovy:736)
at grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper$7.writeTo(DefaultGrailsJsonViewHelper.groovy:713)
at grails.plugin.json.view.JsonViewTemplate.json(JsonViewTemplate.groovy:126)
at grails.plugin.json.view.JsonViewTemplate.json(JsonViewTemplate.groovy:149)
at zcrm_api_TSCell_show_gson.run(zcrm_api_TSCell_show_gson:7)
at grails.plugin.json.view.JsonViewTemplate.doWrite(JsonViewTemplate.groovy:35)
at grails.views.AbstractWritableScript.writeTo(AbstractWritableScript.groovy:30)
... 26 common frames omitted
Thanks in advance.
That code shouldn't compile, but Groovy is too 'helpful' sometimes and allowed it through. You named an instance variable the same as its class, TSCell, and this turns out to be an interesting block of code to see how Groovy handles disambiguation between instance and static method calls.
For the first line, since you have TSCell TSCell it's possible for the compiler to know that the one on the left is the class name and the one on the right is an instance variable, since there's no other valid interpretation of those tokens.
In the third line it's not as clear whether the class or instance variable is being checked for null, but I tried this out locally and it's the instance variable.
TSCell.hasErrors() could be interpreted as a static method call on the class or a call on the instance, but since that method isn't static, Groovy invokes it on the instance and it succeeds. The same logic has to be applied to the save call, but again since it's not a static method it's call on the instance and succeeds.
And then on the last line of the method, kaboom, your luck ran out after four successful calls. There are a few overloads of the respond method and you end up calling respond(Object, Map), and that's valid for either TSCell the class, or TSCell the instance of the TSCell class. Groovy picked the one that wasn't what you intended and the one that isn't supported inside the respond method.
Groovy shares Java's variable and class naming conventions, i.e. class names start with an uppercase letter and instance variable names start with a lowercase letter. It's one thing to just tell people that this is a good approach, but an example like this makes it a lot more obvious why it's a bad idea to use uppercase instance variable names (you should be able to look at the variable and not need to see its declaration to know if it's a class or var name) and why it's even worse to use the same name as the class.
This error is probably caused because you named parameter with same name as class name.
I would suggest that you change name of the variable to lowercase (this is groovy and java naming convention).
def update(TSCell tsCell) { //you can also just write tsCell without type
println "in update method"
if (tsCell == null) {
transactionStatus.setRollbackOnly()
render status: NOT_FOUND
return
}
if (tsCell.hasErrors()) {
transactionStatus.setRollbackOnly()
respond tsCell.errors, view:'edit'
return
}
tsCell.save flush:true
respond tsCell, [status: OK, view:"show"]
}
The problem was in the call curl. As documentation says Grails has built in support for Content negotiation using either the HTTP Accept header, an explicit format request parameter or the extension of a mapped URI.
So the adding -H "Accept: application/xml" to the above curl call resolved the issue.
Related
My application parses settings using "typesafe.config" and then converts the Config object into an instance of a case class using "ficus". The case class currently has 19 constructor arguments. And everything works normally. However, when I add a new argument and a new corresponding field in my "settings.conf", I get the following exception:
An exception or error caused a run to abort: MyCaseClass.<init>(Ljava/lang/String;Lscala/Option;Lscala/Option;IZLscala/collection/Seq;Ljava/lang/String;ILscala/concurrent/duration/FiniteDuration;ZLscala/Option;Lscala/Option;ILscala/Option;Lscala/concurrent/duration/FiniteDuration;Ljava/lang/String;Ljava/lang/String;II)V
java.lang.NoSuchMethodError: MyCaseClass.<init>(Ljava/lang/String;Lscala/Option;Lscala/Option;IZLscala/collection/Seq;Ljava/lang/String;ILscala/concurrent/duration/FiniteDuration;ZLscala/Option;Lscala/Option;ILscala/Option;Lscala/concurrent/duration/FiniteDuration;Ljava/lang/String;Ljava/lang/String;II)V
I can see the "typesafe.config" is correctly parsing my new field into the Config object. But ficus then throws this exception. The new field and the new case class constructor argument have exactly the same name, as they should.
Any ideas why this may be happening?
The concrete problem is documented in the following commits:
1) https://github.com/ceilican/Scorex/commit/133157a6ad070cad7a57624c511ee917133ed5f1
2) https://github.com/ceilican/Scorex/commit/074e0bc5add3c666b0943497a5579f3fd365084d
3) https://github.com/ceilican/Scorex/commit/7c8d3475377a17b2a5383bf3a99d797650ca8bc3
The first two commits are working. With the third one, the exception mentioned above is thrown.
As you can see, there is not much conceptual difference between commits 2 and 3. I don't understand why commit 2 works, whereas commit 3 doesn't.
For a moment I thought it could be because of the large number of arguments in the case class, but the following commit shows that the problem also happens when I add the new field to a smaller case class:
4) https://github.com/ceilican/Scorex/commit/1c253b2b526db1539fa674069232cf02784c4bfb
The same kind of exception is thrown when I try to run the code after commit 4.
Is this a bug in Ficus?
After doing sbt clean on the main project and on subprojects, the problem stopped happening. My guess is that Ficus's macro magic generates functions based on my case classes, but they are not re-generated when the case classes are modified. Then, when Ficus tries to use the outdated functions that are incompatible with the new case classes, the exception is thrown.
Interestingly, the lack of re-generation happens only when I modify "nested" case classes. If the config file is:
main {
nested {
param: 0
}
}
with case classes:
case class MainCaseClass(nested: NestedCaseClass)
case class NestedCaseClass(param: Int)
Then, modifying MainCaseClass does not cause problems, but modifying NestedCaseClass does.
I am developing an iOS application and am trying to integrate Typhoon into the testing. I am currently trying to mock out a dependency in a view controller that comes from the storyboard, so with in my assembly:
public dynamic var systemComponents: SystemComponents!
public dynamic func storyboard() -> AnyObject {
return TyphoonDefinition.withClass(TyphoonStoryboard.self) {
(definition) in
definition.useInitializer("storyboardWithName:factory:bundle:") {
(initializer) in
initializer.injectParameterWith("Main")
initializer.injectParameterWith(self)
initializer.injectParameterWith(NSBundle.mainBundle())
}
}
}
I want to create a CameraModeViewController (the class I am unit testing) with its dependency upon a system-camera-functions-providing protocol mocked out. The dependency is dynamic var cameraProvider: CameraAPIProvider?. I think I correctly created a replacement collaborating assembly to replace systemComponents; MockSystemComponents is a subclass of SystemComponents that overrides functions. This is where I inject the mock:
let assembly = ApplicationAssembly().activateWithCollaboratingAssemblies([
MockSystemComponents(camera: true)
])
let storyboard = assembly.storyboard()
subject = storyboard.instantiateViewControllerWithIdentifier("Camera-Mode") as! CameraModeViewController
The next line of code in the tests is let _ = subject.view, which I learned is a trick to call viewDidLoad and get all the storyboard-linked IBOutlets, one of which is required for this test.
However, I am getting very mysterious result: sometimes but not always, all the tests fail because in the viewDidLoad I make a call to the dependency (cameraProvider), and I get an "unrecognized message sent to class" error. The error seems to indicate that at the time the message is sent (which is a correct instance method in protocol CameraAPIProvider) the field is currently a CLASS and not an instance: it interprets the message as +[MockSystemCamera cameraStreamLayer] as reported in the error message.
~~~BUT~~~
Here's the kicker: if I add a breakpoint between the calls to assembly.storyboard() and subject.view, the tests always pass. Everything is set up correctly, and the message is correctly sent to an instance without this "class method" bogus interpretation. Therefore, I have to wonder if Typhoon does some kind of asynchronous procedure in the injection that I have to wait for? Possibly only when dealing with storyboard-delivered view controllers? And if so, is there any way to make sure it blocks?
After digging around in Typhoon's source for a while, I get the impression that in the TyphoonDefinition(Instance Builder) initializeInstanceWithArgs:factory: method there is an __block id instance that is temporarily a Class type, and then is replaced with an instance of that type; and possibly this can be called asynchronously without blocking, so the injected member is left as a Class type?
UPDATE: Adding the code for MockSystemComponents(camera:). Note that SystemComponents inherits from TyphoonAssembly.
#objc
public class MockSystemComponents: SystemComponents {
var cameraAvailable: NSNumber
init(camera: NSNumber) {
self.cameraAvailable = camera
super.init()
}
public override func systemCameraProvider() -> AnyObject {
return TyphoonDefinition.withClass(MockSystemCamera.self) {
(definition) in
definition.useInitializer("initWithAvailable:") {
(initializer) in
initializer.injectParameterWith(self.cameraAvailable)
}
}
}
}
UPDATE #2: I tried replacing the constructor injection in the MockSystemComponents.systemCameraProvider() with a property injection. Different issue, but I suspect it's equivalent in cause: now, the property that is injected (declared optional) is still nil some of the time when I go to unwrap it (but not always -- probably about 4/5 of test runs fail, about the same as before).
UPDATE #3: have tried using the following code block, using factory construction according to this answer (note that setting factory directly didn't work as that OP did, but I think I correctly used the feature added in response to Jasper's issue). The results are the same as when using property injection like Update #2 above), so no dice there.
This issue was in fact arising even before the call to the instantiation. In fact, the problem was assemblies aren't generally intended to be stateful. There are a few ways to get around this, but the one I used -- having a member variable and an initializer method -- is NOT recommended. The problem with doing this is that in the activateWithCollaboratingAssemblies method, all the instance methods of the assembly are enumerated for definitions, and initializers will actually get called on the collaborating assembly. Consequently, even if you create your assembly with an initializer, it may get called again with a bogus value.
Note that the reason there appeared to be async behavior is actually that there is nondeterministic order in which definitions are assembled (property of storing them in an NSDictionary). This means that if activateWithCollaboratingAssemblies happens to enumerate methods which depend on state first, they'll work fine; but if the initializer is enumerated first, and the state is destroyed, definitions that are created after will be borked.
https://github.com/scala/scala/blob/2.11.x/src/library/scala/Predef.scala#L230
??? in scala is a function defined in predef that throws a NotImplementedError
In my project I am using Google Guice in order to inject dependencies, and thought it would be good to have a similar function that throws an exception if the injection never happened, in order to catch missing usages of the injector or missing #Inject annotations.
In my project I have a class that is expecting to be injected
class OScoreboard {
#Inject
val source :Provider[ScoreboardBuilder] = injected;
}
and an object
class ExpectedInjectionException(message: String = null, cause: Throwable = null) extends RuntimeException
object injected extends Nothing{
def apply : Nothing = {
throw new ExpectedInjectionException("Expected an injection")
}
}
But I get the error that injected isn't of type Provider[ScoreboardBuilder]
Am I abusing apply? How else can I reference the scala function apply (or even with a different name) without referencing the object injected?
Also I suspect that even if I fix this error, the function will be eagerly run causing the exception before injection happens, does that mean I need to make every injected field lazy, or is there another solution?
Edit:
The problem was my understanding of Scala.
vals are eagerly computed, so the ???-like function is immediately executed on class construction (which since it's using field injection, occurs immediately before injection happens) causing the field to never be injected.
Values like final fields in Java CAN be injected, because it's only a restriction by the byte code verifier. final fields can be written to fine by using reflection (which Guice does).
In order to answer this question there needs to be a way to delay the execution of the ???-like function/value until the field is first read. I'm unsure how, or if it is even possible. The other option is just to initialize them to null. But that will result in NullPointerExceptions which are famously unhelpful. I was hoping to use a null-like error with an explanation that the injection failed.
First of all: in one place you wrote INJECTED and in the other place injected. I'll assume this was a typo and that you mean the same thing with both.
An assignment like this:
val source :Provider[ScoreboardBuilder] = INJECTED;
will not work because you are trying to assign the object INJECTED to a variable of type Provider[ScoreboardBuilder]. The object is not of that type, so you can't do that assignment.
Maybe you expected that the object would behave like a function and that its apply method would automatically be called, but that's not how it works.
You can define INJECTED as a method inside your class:
class OScoreboard {
#Inject
val source :Provider[ScoreboardBuilder] = INJECTED
private def INJECTED : Nothing =
throw new ExpectedInjectionException("Expected an injection")
}
Or you can put it in a separate object, but then you'd have to import it in your class:
object injected {
def INJECTED : Nothing =
throw new ExpectedInjectionException("Expected an injection")
}
class OScoreboard {
import injected._
#Inject
val source :Provider[ScoreboardBuilder] = INJECTED
}
The problem was my understanding of Scala.
vals are eagerly computed, so the ??? function is immediately executed on class construction (which since it's using field injection, occurs immediately before injection happens) causing the exception to be thrown.
Making it lazy results in the injection happening using reflection without the exception being thrown on construction. HOWEVER the generated Java code is not aware that this happens. So when the injected value is accessed for the first time, the generated code replaces the injected reference with ??? then proceeds to throw the exception.
There is no way that I can see in order to make this work.
Exception:
The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.
Method where exception happened:
/// <summary>
/// Initializes a new DSAplcEntities object using the connection string found in the 'DSAplcEntities' section of the application configuration file.
/// </summary>
public DSAplcEntities() : base("name=DSAplcEntities", "DSAplcEntities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
What exactly does this exception mean and how can I fix it?
Found the solution. The problem was that I was using WCF Services in my project and I did not copy the connection string to the App.Config inside the service solution.
The string arguments passed to the base class constructor are used to pass in either a named connection string (defined externally in a config file) or the connection string itself, depending on which constructor is invoked.
It looks like you're invoking the constructor on ObjectContext that takes two arguments, the first of which must be a valid connection string. The string you are passing in is not a valid EF connection string, which is why you get the error message from EF.
Check if you have the actual connection string defined in your config file. Note what name it has been defined with and pass in that name as the first argument (and if that doesn't work, try removing the second argument - I'm not sure if the method you're calling accepts a named connection string).
I am running into an issue with GWT :
The exception stack looks like :
Caused by: java.lang.RuntimeException: Deferred binding failed for 'com.cme.reg.fltrs.common.service.AnnouncementService' (did you forget to inherit a required module?)
at com.google.gwt.dev.shell.GWTBridgeImpl.create(GWTBridgeImpl.java:53)
at com.google.gwt.core.client.GWT.create(GWT.java:98)
at com.cme.reg.fltrs.client.sharedui.utils.ServiceFactory.getAnnouncementService(ServiceFactory.java:117)
at com.cme.reg.fltrs.client.announcement.AddMaintainAnnouncementModel.saveAnnouncement(AddMaintainAnnouncementModel.java:36)
at com.cme.reg.fltrs.client.announcement.AddMaintainAnnouncementPanel.save(AddMaintainAnnouncementPanel.java:260)
at com.cme.reg.fltrs.client.announcement.AddMaintainAnnouncementPanel$6.onClick(AddMaintainAnnouncementPanel.java:168)
at com.cme.libs.gwt.client.widgets.events.CMEClickListener.onEvent(CMEClickListener.java:10)
at com.cme.libs.gwt.client.widgets.events.CMEListenerCollection.fireEvent(CMEListenerCollection.java:51)
at com.cme.libs.gwt.client.widgets.CMEButton$1.onClick(CMEButton.java:30)
at com.google.gwt.event.dom.client.ClickEvent.dispatch(ClickEvent.java:54)
at com.google.gwt.event.dom.client.ClickEvent.dispatch(ClickEvent.java:1)
at com.google.gwt.event.shared.GwtEvent.dispatch(GwtEvent.java:1)
at com.google.web.bindery.event.shared.SimpleEventBus.doFire(SimpleEventBus.java:193)
at com.google.web.bindery.event.shared.SimpleEventBus.fireEvent(SimpleEventBus.java:88)
at com.google.gwt.event.shared.HandlerManager.fireEvent(HandlerManager.java:127)
Its failing at : announcementService = GWT.create(AnnouncementService.class);
Notes:
I have my service class : AnnouncementService
#RemoteServiceRelativePath( "announcement.srvc" ) has been added to AnnouncementService.
Async service class: AnnouncementServiceAsync
Configurations.xml :
entry key="**/announcement.srvc" value-ref="announcementServiceServlet"
Any help, where I am doing wrong or missing anything ?
Thanks Thomas.
Few The things to be checked:
1.Service must have a matching ServiceAsync class
2. Make sure all types used in Service implement IsSerializable
I was missing these two condition at few places.
If you're getting a deferred binding error with your RPC, then in addition to checking there is a matching Async interface, another thing to check is to make sure that you have the same methods in the following 3 places:
Synchronous interface
Asynchronous interface
Service implementation class
I got a similar "deferred binding" error when I accidentally had an extra method in my Synchronous (regular) interface that was missing in the Async interface and implementation class, but my IDE (IntelliJ IDEA 12) did not flag any files as having errors. When I finally remembered that I had recently removed a method from my service, I went into the Synchronous interface and saw that I had forgotten to remove that method's signature from the synchronous interface. Removing it so that the signatures matched in all three files fixed the Deferred binding error.