Extend Corda serialization for a 3rd-party class - corda

TL; DR;
I need Corda to serialize JSONObject from JDK. I suspect I can add a custom parser for it, but I can't figure out how.
Full story:
So I have a bunch of classes that act as semy-type safe wrappers around a JSON api. An example:
#CordaSerializable
class ClaimReq(val json: JSONObject) {
val proverDid: String = json.getString("prover_did")
val credDefId: String = json.getString("cred_def_id")
}
The problem appeared when I tried to send such a class through a Corda channel. The system had a problem serializing the org.json.JSONObject:
java.io.NotSerializableException: No constructor for deserialization found for class org.json.JSONObject.
at net.corda.nodeapi.internal.serialization.amqp.SerializationHelperKt.constructorForDeserialization(SerializationHelper.kt:50) ~[corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForObject(Schema.kt:456) ~[corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.access$fingerprintForObject(Schema.kt:1) ~[corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt$fingerprintForType$3.invoke(Schema.kt:423) ~[corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt$fingerprintForType$3.invoke(Schema.kt) ~[corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintWithCustomSerializerOrElse(Schema.kt:345) ~[corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForType(Schema.kt:417) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForObject(Schema.kt:459) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.access$fingerprintForObject(Schema.kt:1) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt$fingerprintForType$3.invoke(Schema.kt:423) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt$fingerprintForType$3.invoke(Schema.kt) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintWithCustomSerializerOrElse(Schema.kt:345) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForType(Schema.kt:417) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForType$default(Schema.kt:352) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForType(Schema.kt:328) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.ObjectSerializer.(ObjectSerializer.kt:34) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializerFactory$makeClassSerializer$1.apply(SerializerFactory.kt:271) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializerFactory$makeClassSerializer$1.apply(SerializerFactory.kt:40) [corda-node-api-3.1-corda.jar:?]
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1688) [?:1.8.0_171]
at net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.makeClassSerializer(SerializerFactory.kt:255) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.get(SerializerFactory.kt:100) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput.writeObject$node_api(SerializationOutput.kt:98) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput.writeObject$node_api$default(SerializationOutput.kt:97) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput.writeObject$node_api(SerializationOutput.kt:78) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput$_serialize$1$1.invoke(SerializationOutput.kt:64) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput$_serialize$1$1.invoke(SerializationOutput.kt:22) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationHelperKt.withList(SerializationHelper.kt:401) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput$_serialize$1.invoke(SerializationOutput.kt:63) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput$_serialize$1.invoke(SerializationOutput.kt:22) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationHelperKt.withDescribed(SerializationHelper.kt:390) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput._serialize$node_api(SerializationOutput.kt:62) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput.serialize(SerializationOutput.kt:36) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.amqp.AbstractAMQPSerializationScheme.serialize(AMQPSerializationScheme.kt:128) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl$serialize$1$1.invoke(SerializationScheme.kt:126) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl$serialize$1$1.invoke(SerializationScheme.kt:86) [corda-node-api-3.1-corda.jar:?]
at net.corda.core.serialization.SerializationFactory.withCurrentContext(SerializationAPI.kt:66) [corda-core-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl$serialize$1.invoke(SerializationScheme.kt:126) [corda-node-api-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl$serialize$1.invoke(SerializationScheme.kt:86) [corda-node-api-3.1-corda.jar:?]
at net.corda.core.serialization.SerializationFactory.asCurrent(SerializationAPI.kt:80) [corda-core-3.1-corda.jar:?]
at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl.serialize(SerializationScheme.kt:126) [corda-node-api-3.1-corda.jar:?]
at net.corda.core.serialization.SerializationAPIKt.serialize(SerializationAPI.kt:221) [corda-core-3.1-corda.jar:?]
at net.corda.core.serialization.SerializationAPIKt.serialize$default(SerializationAPI.kt:220) [corda-core-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.createSessionData(FlowStateMachineImpl.kt:353) [corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.send(FlowStateMachineImpl.kt:235) [corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowSessionImpl.send(FlowSessionImpl.kt:52) [corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowSessionImpl.send(FlowSessionImpl.kt:56) [corda-node-3.1-corda.jar:?]
at com.luxoft.blockchainlab.corda.hyperledger.indy.flow.IssueClaimFlow$Prover.call(IssueClaimFlow.kt:85) [main/:?]
at com.luxoft.blockchainlab.corda.hyperledger.indy.flow.IssueClaimFlow$Prover.call(IssueClaimFlow.kt:71) [main/:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) [corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:44) [corda-node-3.1-corda.jar:?]
at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) [quasar-core-0.7.9-jdk8.jar:0.7.9]
So I fixed the problem with a scpecific constructor and a getter:
#CordaSerializable
class ClaimReq(val json: JSONObject) {
val proverDid: String = json.getString("prover_did")
val credDefId: String = json.getString("cred_def_id")
#ConstructorForDeserialization constructor(str: String) : this(JSONObject(str))
val str = json.toString()
}
Unfortunately that solution requires to add 2 lines to every class declaration. Is there any way I could abstract it out, like in a super-class? Or maybe I could extend Corda serialization with a custom parcer to support JSONObject?

Any classes serialised by the Corda framework that have more than one constructor require one of the constructors to be annotated with #ConstructorForDeserialization. Obviously, there is no constructor with this annotation in JSONObject.
You need to provide a custom serializer for the JSONObject class. See an example of defining a custom serializer here: https://docs.corda.net/head/cordapp-custom-serializers.html#example.
If this serializer is on the classpath, it will be used by the node at runtime.

Related

Catching and responding to the Connman 'RequestInput' method call with QtDBus

I'm building a simple Qt-based application for monitoring and connecting to WiFi networks. I'm interfacing with Connman via its D-Bus APIs, and am able to scan for available networks, turn on/off technologies and register an agent as expected. I'm currently unable to provide the requested passphrase when the Connman RequestInput method is called (when attempting to connect to a protected/secure network), as I'm unsure how to bind the RequestInput method with a function in Qt.
Below is some indicative code which outlines the approach:
//Create a QDBusConnection systemBus() object
QDBusConnection connection = QDBusConnection::systemBus();
//Ensure the systemBus() connection is established
if (!connection.isConnected()) {
qDebug() << "Connection error.";
}
//Create a Connman Manager D-Bus API interface object
QDBusInterface manager("net.connman", "/", "net.connman.Manager", connection);
//Register an agent with the Connman Manager API
manager.call("RegisterAgent", QVariant::fromValue(QDBusObjectPath("/test/agent")));
//Attempt to bind the mySlot() function with the net.connman.Agent RequestInput method
//This does not currently work
connection.connect("",
"/test/agent",
"net.connman.Agent",
"RequestInput",
this,
SLOT(mySlot(QDBusObjectPath, QVariantMap)));
//Create a Connman Service D-Bus API interface object (for a specific WiFi Service)
QDBusInterface service("net.connman",
"/net/connman/service/[WIFI SERVICE]",
"net.connman.Service",
connection);
//Attempt to connect to the secure WiFi network
//Note: this network has not previously been connected, so the RequestInput method is guaranteed to be called
service.call("Connect");
QVariantMap myClass::mySlot(const QDBusObjectPath &path, const QVariantMap &map)
{
//Connman Agent RequestInput() method received
}
As commented above, the attempted binding of the /test/agent path, net.connman.Agent interface and RequestInput method to the mySlot() function does not work; there are no errors reported but the mySlot() function is never called. If I enable debugging with the QDBUS_DEBUG environment variable, I receive the following:
QDBusConnectionPrivate(0xffff74003a00) got message (signal): QDBusMessage(type=MethodCall, service=":1.3", path="/test/agent", interface="net.connman.Agent", member="RequestInput", signature="oa{sv}", contents=([ObjectPath: /net/connman/service/[WIFI SERVICE]], [Argument: a{sv} {"Passphrase" = [Variant: [Argument: a{sv} {"Type" = [Variant(QString): "psk"], "Requirement" = [Variant(QString): "mandatory"]}]]}]) )
The above is exactly what I'd expect; the RequestInput method is being called for the /test/agent path on the net.connman.Agent interface with the oa{sv} signature.
My questions:
How do I 'connect' to the RequestInput method call, such that my mySlot() function can parse the RequestInput method data?
How do I return the required QVariantMap from within mySlot()?
From the debug output it appears that ConnMan is doing a MethodCall, but QDBusConnection::connect() is for handling DBus singals, which is why your slot is not invoked.
You need to register an object implementing the net.connman.Agent interface onto the corresponding path, so that ConnMan can invoke your methods:
class ConnManAgent : public QObject {
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "net.connman.Agent")
public:
ConnManAgent(QObject *parent = nullptr);
Q_INVOKABLE QVariantMap RequestInput(const QDBusObjectPath &, const QVariantMap &);
// ... Rest of the net.connman.Agent interface
};
and then register it on the respective path:
connection.registerObject(
QStringLiteral("/test/agent"),
new ConnManAgent(this),
QDBusConnection::ExportAllInvokables);
This exports all methods marked with Q_INVOKABLE to DBus. You might also mark them as Q_SLOTS and use ExportAllSlots, that's mostly up to you.

Counterparty sent session rejection message at unexpected time with message class com.upgrade.CustomContractUpgradeFlow$Initiate is not registered

Project: ContractUpgradeFlow
Project Link: https://github.com/corda/contract-upgrades
I tried to create my own Contract Upgrade flow, so I copied the code for contract upgrade as it is, but after executing it is not able to upgrade the contract.
Steps I followed:
Connect to PartyA and PartyB's nodes via RPC
Issue a state with the old contract
Upgrade the state to use the new contract
Wait ten seconds for the contract upgrade to propagate
Log the state to show that its contract has been upgraded
Please find attached code and error log.
Code:
package com.upgrade
import co.paralleluniverse.fibers.Suspendable
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.PrivacySalt
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.UpgradedContract
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SignableData
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.flows.*
import net.corda.core.internal.ContractUpgradeUtils
import net.corda.core.transactions.SignedTransaction
object CustomContractUpgradeFlow {
#StartableByRPC
class Authorise(
val stateAndRef: StateAndRef<*>,
private val upgradedContractClass: Class<out UpgradedContract<*, *>>
) : FlowLogic<Void?>() {
// DOCEND 1
#Suspendable
override fun call(): Void? {
val upgrade = upgradedContractClass.newInstance()
if (upgrade.legacyContract != stateAndRef.state.contract) {
throw FlowException("The contract state cannot be upgraded using provided UpgradedContract.")
}
serviceHub.contractUpgradeService.storeAuthorisedContractUpgrade(stateAndRef.ref, upgradedContractClass)
return null
}
}
#InitiatingFlow
#StartableByRPC
class Initiate<OldState : ContractState, out NewState : ContractState>(
originalState: StateAndRef<OldState>,
newContractClass: Class<out UpgradedContract<OldState, NewState>>
) : AbstractStateReplacementFlow.Instigator<OldState, NewState, Class<out UpgradedContract<OldState, NewState>>>(originalState, newContractClass) {
#Suspendable
override fun assembleTx(): AbstractStateReplacementFlow.UpgradeTx {
val tx = ContractUpgradeUtils.assembleUpgradeTx(originalState, modification, PrivacySalt(), serviceHub)
val participantKeys = originalState.state.data.participants.map { it.owningKey }.toSet()
val myKey = serviceHub.keyManagementService.filterMyKeys(participantKeys).single()
val signableData = SignableData(tx.id, SignatureMetadata(serviceHub.myInfo.platformVersion, Crypto.findSignatureScheme(myKey).schemeNumberID))
val mySignature = serviceHub.keyManagementService.sign(signableData, myKey)
val stx = SignedTransaction(tx, listOf(mySignature))
return AbstractStateReplacementFlow.UpgradeTx(stx)
}
}
}
Logs:
[WARN ] 2018-06-14T06:30:35,936Z [Node thread-1] flow.[079185a0-c4a4-47eb-9a70-145d42cc2d9d].run - Terminated by unexpected exception {}
net.corda.core.flows.UnexpectedFlowEndException: Counterparty sent session rejection message at unexpected time with message class com.upgrade.CustomContractUpgradeFlow$Initiate is not registered
at net.corda.node.services.statemachine.FlowStateMachineImpl.erroredEnd(FlowStateMachineImpl.kt:484) ~[corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.confirmNoError(FlowStateMachineImpl.kt:471) ~[corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.waitForMessage(FlowStateMachineImpl.kt:431) ~[corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.receiveInternal(FlowStateMachineImpl.kt:363) ~[corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.waitForConfirmation(FlowStateMachineImpl.kt:333) ~[corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.initiateSession(FlowStateMachineImpl.kt:423) ~[corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.sendAndReceive(FlowStateMachineImpl.kt:185) ~[corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:29) ~[corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowSessionImpl.sendAndReceive(FlowSessionImpl.kt:40) ~[corda-node-3.1-corda.jar:?]
at net.corda.core.flows.DataVendingFlow.sendPayloadAndReceiveDataRequest(SendTransactionFlow.kt:70) ~[corda-core-3.1-corda.jar:?]
at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:48) ~[corda-core-3.1-corda.jar:?]
at net.corda.core.flows.DataVendingFlow.call(SendTransactionFlow.kt:31) ~[corda-core-3.1-corda.jar:?]
at net.corda.core.flows.FlowLogic.subFlow(FlowLogic.kt:290) ~[corda-core-3.1-corda.jar:?]
at net.corda.core.flows.AbstractStateReplacementFlow$Instigator.getParticipantSignature(AbstractStateReplacementFlow.kt:108) ~[corda-core-3.1-corda.jar:?]
at net.corda.core.flows.AbstractStateReplacementFlow$Instigator.collectSignatures(AbstractStateReplacementFlow.kt:92) ~[corda-core-3.1-corda.jar:?]
at net.corda.core.flows.AbstractStateReplacementFlow$Instigator.call(AbstractStateReplacementFlow.kt:68) ~[corda-core-3.1-corda.jar:?]
at net.corda.core.flows.AbstractStateReplacementFlow$Instigator.call(AbstractStateReplacementFlow.kt:50) ~[corda-core-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) [corda-node-3.1-corda.jar:?]
at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:44) [corda-node-3.1-corda.jar:?]
at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.RunnableFiberTask.doExec(RunnableFiberTask.java:100) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at co.paralleluniverse.fibers.RunnableFiberTask.run(RunnableFiberTask.java:91) [quasar-core-0.7.9-jdk8.jar:0.7.9]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_171]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_171]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [?:1.8.0_171]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [?:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_171]
at net.corda.node.utilities.AffinityExecutor$ServiceAffinityExecutor$1$thread$1.run(AffinityExecutor.kt:62) [corda-node-3.1-corda.jar:?]
AbstractStateReplacementFlow.Instigator will make a call to CollectSignaturesFlow to gather the signatures of the counterparties that need to authorise the upgrade.
You therefore need to provide a responder flow for your CustomContractUpgradeFlow.Initiate that will call SignTransactionFlow.

MissingServletRequestParameterException : Calling post method in Angular.js

I'm trying to call a uri named ant/talk with post method in Angular.js.
In my code, I called using $http.post method in javascript with data.
$http.post('ant/create', {
content : $scope.content,
type : chatType,
point : point
}).then(function(response) { /* if successful request */ }
However, in spring controller just told me MissingServletRequestParameterException
#Controller
#RequestMapping("/ant/*")
public class AntTalkCont {
....
#RequestMapping(value = "/create", method = RequestMethod.POST, produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
#ResponseBody
public String createProcess(HttpServletRequest request, Locale locale, Model model
, #RequestParam("content") String content) {
String content2 = request.getParameter("content");
logger.debug("content = {}", content);
logger.debug("content by request = {}", content2);
....
But I declared #RequestParam in java controller above, the spring controller throwed that exception. Though I removed RequestParam annotation and used request.getParameter also got null value.
I can append content on url like this ant/create?content='+$scope.content but the $scope.content can be longer than 512 bytes so I want to use data object in post request.
In spring controlller, how can I fix it properly?
Here is full stacktrace
16:59:17.546 [http-apr-30802-exec-80] DEBUG
o.s.w.s.m.m.a.ServletInvocableHandlerMethod - Error resolving argument
[3] [type=java.lang.String] HandlerMethod details: Controller
[kr.stocktalk.webchat.cont.AntTalkCont] Method [public
java.lang.String
kr.stocktalk.webchat.cont.AntTalkCont.createProcess(javax.servlet.http.HttpServletRequest,java.util.Locale,org.springframework.ui.Model,java.lang.String)]
org.springframework.web.bind.MissingServletRequestParameterException:
Required String parameter 'content' is not present at
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:195)
~[spring-web-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:104)
~[spring-web-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
~[spring-web-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
[spring-web-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
[spring-web-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
[spring-webmvc-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
[spring-webmvc-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
[spring-webmvc-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
[spring-webmvc-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
[spring-webmvc-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
[spring-webmvc-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
[spring-webmvc-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
[spring-webmvc-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
[servlet-api.jar:na] at
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
[spring-webmvc-4.3.0.RELEASE.jar:4.3.0.RELEASE] at
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
[servlet-api.jar:na] at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
[catalina.jar:8.0.24] at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
[catalina.jar:8.0.24] at
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
[tomcat-websocket.jar:8.0.24] at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
[catalina.jar:8.0.24] at
org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
[catalina.jar:8.0.24] at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
[catalina.jar:8.0.24] at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
[catalina.jar:8.0.24] at
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
[catalina.jar:8.0.24] at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
[catalina.jar:8.0.24] at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
[catalina.jar:8.0.24] at
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:617)
[catalina.jar:8.0.24] at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
[catalina.jar:8.0.24] at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
[catalina.jar:8.0.24] at
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
[tomcat-coyote.jar:8.0.24] at
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
[tomcat-coyote.jar:8.0.24] at
org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2503)
[tomcat-coyote.jar:8.0.24] at
org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2492)
[tomcat-coyote.jar:8.0.24] at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[na:1.8.0_65] at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[na:1.8.0_65] at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
[tomcat-util.jar:8.0.24] at java.lang.Thread.run(Thread.java:745)
[na:1.8.0_65]

Spring MVC + Shiro + Junit Testing

Hello I am working on Spring MVC application. Shiro is the security framework for my application. Now I want to write unit tests for my application. I am facing some issues with getting shiro's SecurityUtils class in my controllers while testing. I am pasting my code snippets below. I am re-using my bean definitions for both testing and development.
import org.apache.shiro.SecurityUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.nsl.eds.domain.User;
#Controller
public class HomeController {
#RequestMapping({ "/", "/home" })
public String showHome(Model model) {
model.addAttribute("user",(User) SecurityUtils.getSubject().getPrincipal());
return "home";
}
}
This is my controller, and below is my Test class
#ContextConfiguration
(
{
//"classpath:beans.xml",
"file:src/main/webapp/WEB-INF/frontController-servlet.xml",
"file:src/main/webapp/WEB-INF/dao-definition.xml",
"file:src/main/webapp/WEB-INF/schemacrawler-context.xml",
"file:src/main/webapp/WEB-INF/security-settings.xml"
}
)
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
public class HomeControllerTest extends AbstractShiroTest {
#Autowired
private WebApplicationContext ctx;
private MockMvc mockMvc;
private Subject subjectUnderTest;
protected MockHttpSession mockSession;
#Before public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
final Authenticate bean = (Authenticate)ctx.getBean("authenticate");
//1. Create a mock authenticated Subject instance for the test to run:
subjectUnderTest = new Subject.Builder(getSecurityManager()).buildSubject();//Mockito.mock(Subject.class);
//expect(subjectUnderTest.isAuthenticated()).andReturn(true);
mockSession = new MockHttpSession(ctx.getServletContext(),
subjectUnderTest.getSession().getId().toString());
//2. Bind the subject to the current thread:
setSubject(subjectUnderTest);
//bean.logon("User01", "User01", mockSession.getId());
//2. Bind the subject to the current thread:
setSubject(subjectUnderTest);
//perform test logic here. Any call to
//SecurityUtils.getSubject() directly (or nested in the
//call stack) will work properly.
}
#Test
public void testShowHome() throws Exception {
mockMvc.perform(
MockMvcRequestBuilders.get("/home"))
.andExpect(status().isOk())
.andExpect(forwardedUrl("/WEB-INF/views/home.jsp"))
.andExpect(model().attributeExists("user"));
}
#After
public void detachSubject()
{
subjectThreadState.clear();
}
}
With final Authenticate bean = (Authenticate)ctx.getBean("authenticate"); uncommented, My Stack trace is
org.apache.shiro.UnavailableSecurityManagerException: No SecurityManager accessible to the calling code, either bound to the org.apache.shiro.util.ThreadContext or as a vm static singleton. This is an invalid application configuration.
at org.apache.shiro.SecurityUtils.getSecurityManager(SecurityUtils.java:123)
at com.nsl.eds.security.shiro.AbstractShiroTest.getSecurityManager(AbstractShiroTest.java:60)
at com.nsl.eds.web.home.HomeControllerTest.setUp(HomeControllerTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
java.lang.NullPointerException
at com.nsl.eds.web.home.HomeControllerTest.detachSubject(HomeControllerTest.java:108)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
With final Authenticate bean = (Authenticate)ctx.getBean("authenticate"); commented, My Stack trace is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'authenticate' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1168)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:281)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:956)
at com.nsl.eds.web.home.HomeControllerTest.setUp(HomeControllerTest.java:52)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
java.lang.NullPointerException
at com.nsl.eds.web.home.HomeControllerTest.detachSubject(HomeControllerTest.java:108)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Also I am having and shiro Abstract authentication class
public abstract class AbstractShiroTest {
protected static ThreadState subjectThreadState;
public AbstractShiroTest() {
}
protected void setSubject(Subject subject) {
clearSubject();
subjectThreadState = createThreadState(subject);
subjectThreadState.bind();
}
protected Subject getSubject() {
return SecurityUtils.getSubject();
}
protected ThreadState createThreadState(Subject subject) {
return new SubjectThreadState(subject);
}
/**
* Clears Shiro's thread state, ensuring the thread remains clean for future test execution.
*/
protected void clearSubject() {
doClearSubject();
}
private static void doClearSubject() {
if (subjectThreadState != null) {
subjectThreadState.clear();
subjectThreadState = null;
}
}
protected static void setSecurityManager(SecurityManager securityManager) {
SecurityUtils.setSecurityManager(securityManager);
}
protected static SecurityManager getSecurityManager() {
return SecurityUtils.getSecurityManager();
}
#AfterClass
public static void tearDownShiro() {
doClearSubject();
try {
SecurityManager securityManager = getSecurityManager();
LifecycleUtils.destroy(securityManager);
} catch (UnavailableSecurityManagerException e) {
//we don't care about this when cleaning up the test environment
//(for example, maybe the subclass is a unit test and it didn't
// need a SecurityManager instance because it was using only
// mock Subject instances)
}
setSecurityManager(null);
}
}
Can any body figure out the issue?
I solved this issue by mocking shiro's org.apache.shiro.mgt.SecurityManager.
#Before
public void setup(){
...
SecurityManager securityManger = mock(SecurityManager.class, RETURNS_DEEP_STUBS);
ThreadContext.bind(securityManger);
...
}

Spring 3 -- IllegalStateException

I am getting an IllegalStateException in my controller. Here is the mapping and signature for my controller, which is what is relevant here.
#RequestMapping(value = "/poll1", method = RequestMethod.POST)
public String processPoll1(#RequestParam String vote, Model model, BindingResult result) {
I am getting the following error, even though my BindingResult argument clearly does follow my Model argument.
java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be immediately after the model attribute argument in the controller method signature: public java.lang.String com.controller.PollController.processPoll1(java.lang.String,org.springframework.ui.Model,org.springframework.validation.BindingResult)
at org.springframework.web.method.annotation.ErrorsMethodArgumentResolver.resolveArgument(ErrorsMethodArgumentResolver.java:62)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:75)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:156)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:647)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:603)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:950)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:859)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:883)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:792)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Check the docs:
http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#d4e13874
BindingResult is only allowed immediately following a command or form object (not Model).

Resources