I am building an RPC interface that calls cordaRPCOps.startFlowDynamic() and got the following error:
Class "class com.sun.proxy.$Proxy29" is not on the whitelist or
annotated with #CordaSerializable.
I accidentally included an extra parameter to the cordaRPCOps.startFlowDynamic() call:
FlowHandle<SignedTransaction> flowHandle = cordaRPCOps.startFlowDynamic(
FungibleTokenRedeem.class,
amount,
issuer,
observers,
queryCriteria,
changeHolder,
cordaRPCOps // !!! Extra parameter !!!
);
Here is the constructor for the Flow:
public FungibleTokenRedeem(Amount<TokenType> amount, Party issuer, List<Party> observers, QueryCriteria queryCriteria, AbstractParty changeHolder) {
this.amount = amount;
this.issuer = issuer;
this.observers = observers;
this.queryCriteria = queryCriteria;
this.changeHolder = changeHolder;
}
Normally when you have too many, too few or the wrong type of parameter to cordaRPCOps.startFlowDynamic() you get a nice error that helps you identify what you did wrong:
net.corda.core.flows.IllegalFlowLogicException: A FlowLogicRef cannot
be constructed for FlowLogic of type
com.template.flows.FungibleToken.FungibleTokenRedeem: due to ambiguous
match against the constructors
In the past when I accidentally included an extra parameter it just happened to be one that is on Corda’s whitelist (i.e. String, List<> etc.). This time the class happened to be class CordaRPCOps (copy and paste mistake) which is not on the whitelist or annotated with #CordaSerializable and this more cryptic error message was the result. I just wanted a record of it in case someone makes the same mistake.
Related
So I am building a complex case here with inheritance and IOC, need to use ActivatorUtilities to inject instances and pass parameters... no matter what I do I get the following error:
System.InvalidOperationException: 'A suitable constructor for type
'blabla.ISimpleTest' could not
be located. Ensure the type is concrete and all parameters of a public
constructor are either registered as services or passed as arguments.
Also ensure no extraneous arguments are provided.'
So in order to discard what could be the problem and ensure there is no constructor issues, I created a very very simple scenario that gives me the same error.
startup.cs
services.AddScoped<ISimpleTest, SimpleTest>();
the class and the interface, very simple here:
public interface ISimpleTest
{
}
public class SimpleTest : ISimpleTest
{
public SimpleTest()
{
}
}
test
var theInstance = ActivatorUtilities.CreateInstance<ISimpleTest>(ServiceProvider);
Additional notes
The ServiceProvider instance is fine (the rest/entire application depends on it).
Tried with and without adding the public constructor(empty params)
Tried also constructor with params, same error.
Tried to specify the params[] parameter, by sending null or empty array, same issue.
Extra test:
Just to confirm it's properly registered, I tried to get the instance using the Service provider, and works without issues:
//No issues this way:
var yyy = ServiceProvider.GetService<ISimpleTest>();
What am I doing here wrong? According to documentations, this should be enough to work
I want to mock the following line of code:
ResponseEntity<String> response = client.callPostService(url, dto, new ParameterizedTypeReference<String>(){});
Attempt
#Test
public void testFunction{
HTTPSClient client = Mockito.mock(HTTPSClient.class);
Mockito.when(client.callPostService(any(String.class),any(Dto.class), new ParameterizedTypeReference<String>{}))
}
I get errors regarding the parameters I have placed.
You shouldn't mix Mockito's argument matchers (like any(), eq() etc.) and the real objects while configuring behavior for a mock.
So, in your case the next would be correct:
Mockito.when(client.callPostService(any(String.class),any(Dto.class), Mockito.any(ParameterizedTypeReference.class))).thenReturn(...)
or (since Java 8):
Mockito.when(client.callPostService(any(String.class),any(Dto.class), Mockito.any())).thenReturn(...)
The latter also doesn't raise the compiler warning about the unchecked cast of generic type because of enhanced type inference.
I'd like to initiate a flow in Corda (v3.3) shell with
flow start IOUIssueFlow state: { newIOUState: { amount: $100 } }
(the rest of the flow parameters are cut for brevity.)
however the parsing fails with
No matching constructor found:
- [com.template.IOUState]: Could not parse as a command: Instantiation of [simple type, class com.template.IOUState] value failed for JSON
property amount due to missing (therefore NULL) value for creator
parameter amount which is a non-nullable type at [Source: UNKNOWN;
line: -1, column: -1] (through reference chain:
com.template.IOUState["amount"])
IOUIssueFlow's constructor has a single state parameter of type IOUState. IOUState's constructor starts with:
data class IOUState(val amount: Amount<Currency>,
val lender : Party,
val borrower: Party,
val paid : Amount<Currency> = Amount(0, amount.token),
override val linearId: UniqueIdentifier = UniqueIdentifier()): LinearState {...
What am I missing here?
I have the same problem and it looks like bug in jackson. I wasn't able to construct an object as parameter in Corda shell, so I had to fallback to providing all necessary "simple" parameters as input of the Flow and constructing the object inside it.
I'm trying to use websocket in my project.
to do so, I installed the package Microsoft Asp.Net SignalR, which consists of WebSocketHandler abstract class.
i defined a class inheriting WebSocketHandler, but then the compiler complains:
'Microsoft.AspNet.SignalR.WebSockets.WebSocketHandler' does not contain a constructor that takes 0 arguments'.
It seems wierd to me, because the definitioin of WebSocketHandler ctor gets a nullable value, which means the ctor could get no parameter,
the definition looks like this:
protected WebSocketHandler(int? maxIncomingMessageSize);
can anybody tell me what the problem is?
thanks.
It seems wierd to me, because the definitioin of WebSocketHandler ctor gets a nullable value, which means the ctor could get no parameter
No, it doesn't. There's a big difference between receiving a null value for a nullable type, and not receiving a value at all.
If the parameter were optional, that would be a different matter - but it's not. You have to supply an argument convertible to int? in the call. If you want to provide the null value for int?, do so:
var handler = new WebSocketHandler(null);
Or if you want to avoid accidentally using any other single-parameter constructor definitions which may be applicable with a null literal as the argument, you could use:
var handler = new WebSocketHandler((int?) null);
Or:
var handler = new WebSocketHandler(default(int?));
protected member is accessible by derived class instances and there's nothing special about it. Nothing special in the class itself, either # WebSocketHandler.cs.
It just mens you need to pass in a nullable type, it does not mean it can't get any arguments.
int? maxIncomingMessageSize = 0;
var socket = new WebSocketHandler(maxIncomingMessageSize);
In your derived class you could/should define a "constructor that takes 0 arguments".
public class MyHandler : WebSocketHandler
{
// not mandatory
public MyHandler()
:this(null)
{}
// mandatory
public MyHandler(int? maxIncomingMessageSize)
:base(maxIncomingMessageSize)
{}
}
When I Send an instance created by AutoMapper.Mapper.DynamicMap() I run into an error where Rebus seems to want to determine an endpoint for proxy type returned by DynamicMap. This instance will contain an implementation of T assuming T is an interface type.
Is there a way in which I can let Rebus determine an endpoint for the interface type T and not for the implementing type returned by DynamicMap()?
I tried playing around with IDetermineMessageOwnership but had no luck so far.
public static void Send<T>(this IBus bus, object source)
{
var message = Mapper.DynamicMap<T>(source);
bus.Send<T>(message);
}
Thanks in advance!
Sure! In your case, you could create your own implementation of IDetermineMessageOwnership which is the service that Rebus uses to map a message type to an endpoint.
If you want to leverage Rebus' existing logic, you could decorate any chosen strategy and extend it with a keep-looking-at-all-implemented-interfaces-until-one-can-be-mapped strategy like so:
Configure.With(adapter)
.(...)
.MessageOwnership(o => o.FromRebusConfigurationSection())
.Decorators(d => d.AddDecoration(DecorateOwnershipMapping)))
.CreateBus()
.Start();
where DecorateOwnershipMapping would install a decorator on top of whatever is configured like so:
void DecorateOwnershipMapping(ConfigurationBackbone b)
{
b.DetermineMessageOwnership = new CustomizedEndpointMapper(b.DetermineMessageOwnership);
}
and a possible implementation could look like this:
class CustomizedEndpointMapper : IDetermineMessageOwnership
{
readonly IDetermineMessageOwnership wrappedEndpointMapper;
public CustomizedEndpointMapper(IDetermineMessageOwnership wrappedEndpointMapper)
{
this.wrappedEndpointMapper = wrappedEndpointMapper;
}
public string GetEndpointFor(Type messageType)
{
var mappingCandidates = new[] {messageType}
.Concat(messageType.GetInterfaces())
.ToList();
foreach (var typeToTry in mappingCandidates)
{
try
{
return wrappedEndpointMapper.GetEndpointFor(typeToTry);
}
catch{}
}
throw new InvalidOperationException(string.Format("Could not determine the owner of message of type {0} - attempted to map the following types: {1}",
messageType, string.Join(", ", mappingCandidates)));
}
}
thus iterating through the concrete type as well as all inherited interface types when trying to determine the owning endpoint.
In your case, I believe this would work flawlessly when determining the message owner. Only problem is that the serializer will most likely complain, because the dynamically generated type cannot be recognized again when the message is received.
Hence, this trick requires customization of the serializer as well. If you're using the (default) JSON serializer, you might get away with some custom resolvers like so:
Configure.With(...)
.(...)
.Serialization(s => s.UseJsonSerializer()
.AddNameResolver(CustomNameResolver)
.AddTypeResolver(CustomTypeResolver))
.(...)
where CustomNameResolver and CustomTypeResolver are methods that must then take care of mapping the type to a type name and mapping the type name to a type that can then be deserialized into. In order to make this work with AutoMapper, you'll probably need to either
a) somehow use AutoMapper to look up the type of the received message and return that type from CustomTypeResolver, or
b) customize the serializer to have AutoMapper somehow participate in generating the object to be returned
but I must admit that I'm unsure whether the last part will play out smoothly.
A final note: if you succeed in making this work, I suggest you pack up your configuration spells into a reusable extension method on RebusConfigurer so that your endpoints can just go
Configure.With(...)
.(...)
.UseMyFunkyAutoMapperMessagesJustTheWayILikeIt()
.CreateBus().Start();
in all your Rebus endpoints...
I'll appreciate it if you'll let me know how this works out for you! :)