After switching to LambdaModel as an alternative to PropertyModel in one of my forms in my Wicket 8 application I have failing submit tests stating:
java.lang.ClassCastException: java.lang.String cannot be cast to
java.math.BigDecimal
My Form Panel has a NumberTextField which in my working scenario is bound to a PropertyModel.
THIS WORKS
form.add(new NumberTextField<BigDecimal>("myBigDecimalField", new PropertyModel<>(getModel(), "myBigDecimalField")));
THIS DOES NOT WORK
form.add(new NumberTextField<BigDecimal>("myBigDecimalField", LambdaModel.of(getModel(), MyClass::getMyBigDecimalField, MyClass::setMyBigDecimalField)));
The problem is that LambdaModel does not implement IObjectClassAwareModel as PropertyModel does and so when the NumberTextField tries to resolve the type in AbstractTextComponent#152 and subsequentially checks in getModelType if the model is an instance of IObjectClassAwareModel it will not work, as LambdaModel does not implement this interface.
Is this intended that LamdaModel does not implmement IObjectClassAwareModel.
BTW I know that I can fix this issue with explicitly declaring the type class of the NumberTextField.
Regretfully it's quite hard to retrieve any type information from lambdas.
See here for an explanation:
Java: how to resolve generic type of lambda parameter?
So for now it's recommended to pass the type to the component.
Related
Quick question: I've been using autofac with asp.net core in a project and I've noticed that it tries to resolve all types during configuration after updating it to the latest nuget package (going from Autofac.Extensions.DependencyInjection 5.0.1 to 7.0.2). Btw, here's the code that was being used to register the types:
builder.RegisterAssemblyTypes(typeof(Utilizador).Assembly)
.AsImplementedInterfaces()
.AsSelf();
Until now, I wasn't seeing this behavior. The problem with this new approach is that it will try to resolve types that will never be injected through DI. For instance, it complains about public classes that don't have public constructors event though those classes will never be created through DI.
Can someone point me to when this change happened?
Does this mean that now I must filter the types I need explicitly?
Thanks.
This is nothing new.
You can filter those out with something like below:
builder.RegisterAssemblyTypes(ThisAssembly)
.Where(type => type.GetConstructors(BindingFlags.Public).Any())
.AsImplementedInterfaces();
I am new to wicket. There is a confusion in Model, ModelObject defaultModel, genericModel. I need to know the difference between ModelObject and Model, defaultModel and genericModel. Please help me to clear about it.
defaultModel[Object] and genericModel[Object] is the same object, behind the scenes.
Each Component has an IModel and this model brings an java.lang.Object inside. This is the defaultModelObject.
Some specializations of Component, like FormComponent, Form, GenericPanel, etc. use Java generics to make the user code more concrete. For this Wicket uses genericModel[Object] - it is the same Object but casted to its actual type. The casting is in Wicket code, not in the application code.
I'm having an issue with Autofac where it seems like EnableClassInterceptors is interfering with my ability to use .WithParameter(...). When the constructor is being called on Service using the code below, someString is not being populated. Notes:
I've tried using ResolvedParameter instead, it does not help (note: my Resolved parameter still includes the name of the parameter when I tried that)
If I remove EnableClassInterceptors and InterceptedBy, the parameter does get populated properly. This, however, isn't a valid solution as I need the interceptors.
Re-ordering WithParameter, EnableClassInterceptors, and InterceptedBy does not help.
Looking at Type Interceptors, specifically the "Class Interceptors and UsingConstructor" section, on docs.autofac.org, it mentions that using EnableClassInterceptors will cause ConstructUsing to fail. I think something similar might be happening with my scenario below.
Snippet of my registration code looks like this:
var builder = new ContainerBuilder();
builder.RegisterType<Dependency>.As<IDependency>.InstancePerLifetimeScope();
builder.RegisterType<Service>()
.As<IService>()
.WithParameter(new NamedParameter("someString", "TEST"))
.EnableClassInterceptors()
.InterceptedBy(typeof(LogExceptionsInterceptor));
Service's constructor looks something like this:
public class Service : IService
{
public Service(IDependency dependency, string someString)
{
if(dependency == null)
throw ArgumentNullException(nameof(dependency));
if(someString == null)
//**throws here**
throw ArgumentNullException(nameof(someString));
}
}
[Guess] What I'm thinking is happening is that when EnableClassInterceptors is called, a proxy class is generated with a constructor that works on top of the existing one, but the parameter names do not copy over into the proxy class/constructor.
Is this a problem? Is there a way to form the registration that allows both WithParameter and EnableClassInterceptors to be used together? Is it a bug in Autofac?
Your guess is correct: the generated proxy class does not keep the constructor parameter names.
Currently there is no way to influence this in DynamicProxy so this is not a bug of Autofac (although this edge case currently not documented on the Autofac documentation website).
This is how your original Service class's parameters look like:
typeof(Service).GetConstructors()[0].GetParameters()
{System.Reflection.ParameterInfo[2]}
[0]: {ConsoleApplication10.IDependency dependency}
[1]: {System.String someString}
But the generated proxy does not keep the names:
GetType().GetConstructors()[0].GetParameters()
{System.Reflection.ParameterInfo[3]}
[0]: {Castle.DynamicProxy.IInterceptor[] }
[1]: {ConsoleApplication10.IDependency }
[2]: {System.String }
So you have two not very robust options to workaround this limitation with WithParameter:
use the TypedParamter with string as the type:
.WithParameter(new TypedParameter(typeof(string), "TEST"))
However if you have multiple paramters with the same type this won't work
use the PositionalParameter in this case you need to add 1 if the type is proxied
.WithParameter(new PositionalParameter(2, "TEST"))
Another options would be to don't use a primitive string type but create a wrapper e.g. MyServiceParameter or create another service which can provide these string configuration values to your other services.
Am facing an issue while trying to implement an example given over a website.
One of the methods in a class has a signature like this -
private void updateTable(JsArray prices) {....}
And am trying to invoke this method from another method as -
updateTable(JsonUtils.safeEval(response.getText()));
while doing this am seeing a compilation error as -
The method updateTable(JsArray) in the type StockWatcher is not applicable for the arguments (JavaScriptObject)
Though I have just used the exact code displayed in the website, am seeing this error. Not sure what needs to be done. Please help.
The problem has been fixed by making the following change -
updateTable((JsArray)JsonUtils.safeEval(response.getText()));
introduced a casting in the above statement.
This is a follow up to this problem.
That problem was fixed. However, new compiler errors occurred. The compiler errors indicate the following:
The Glimpse.Ado.AlternateType.GlimpseDbCommand class needs a default constructor
The Glimpse.Ado.AlternateType.GlimpseDbConnection class needs a constructor that takes a string (connectionString)
This second problem is strange, because the System.Common.DbConnection class does not have a constructor that takes a string either.