Type cast from Java.Lang.Object to native CLR type in MonoDroid - xamarin.android

How to cast Java.Lang.Object to some native type?
Example:
ListView adapter contains instances of native type Message. When i am trying to get SelectedItem from ListView it returns instance of Message type casted to Java.Lang.Object, but I can't find solution to cast Java.Lang.Object back to Message.
var message = (Message)list.SelectedItem;
// throws Error 5 Cannot convert type 'Java.Lang.Object' to 'Message'
Please Help.

After long time debuging, have found the solution:
public static class ObjectTypeHelper
{
public static T Cast<T>(this Java.Lang.Object obj) where T : class
{
var propertyInfo = obj.GetType().GetProperty("Instance");
return propertyInfo == null ? null : propertyInfo.GetValue(obj, null) as T;
}
}
Usage example:
var message = list.GetItemAtPosition(e.Position).Cast<Message>();
bundle.PutInt("Message", message.ID);
After careful sdk study have found MonoDroid integrated extension for this purpose:
public static TResult JavaCast<TResult>(this Android.Runtime.IJavaObject instance)
where TResult : class, Android.Runtime.IJavaObject
Member of Android.Runtime.Extensions

The least magical way of getting a native type from the Spinner is to call
message = ((ArrayAdapter<Message>)list.Adapter).GetItem(list.SelectedItemPosition);

I used this code from above answer and it works fine to me
public static class ObjectTypeHelper
{
public static T Cast<T>(this Java.Lang.Object obj) where T : class
{
var propertyInfo = obj.GetType().GetProperty("Instance");
return propertyInfo == null ? null : propertyInfo.GetValue(obj, null) as T;
}
}
and this is how I used
var selectedLocation = locationSpinner.SelectedItem.Cast<Location>();
I am able to get my location object fine from spinner

For generic collections, the right answer would be to use JavaList, which is a Java.Lang.Object and also implements IList. But it involves more work that's for sure. This is actually just an adapter for Java's ArrayList implementation.

You could always try the JavaCast<> method (most of the views implement this)(not tested):
var message = list.SelectedItem.JavaCast< Message >();

If for some reason GetChildAtPosition is not possible, serialise the object to json string and then deserialise the string back to native class.

All of the above answers are correct but I found the simplest way for my case was to make the object a subclass of Java.Lang.Object.
For example I'm writing a Android app in Monotouch, mimicking the concept of a UITableView in iOS using the ExpandableListAdapter, which requires the equivalent of UITableViewCells, so I subclassed cell objects from Java.Lang.Object allowing me to implement a subclass of ExpandableListAdapter such as
public override Java.Lang.Object GetChild(int position, int childPosition)
Etc.

it's work for me:
public class HolderHelper<T> : Java.Lang.Object {
public readonly T Value;
public HolderHelper (T value)
{
this.Value = value;
}
}
test:
chkFileName.Tag = new HolderHelper<LinkInfo> (item);
LinkInfo link= (chkFileName.Tag as HolderHelper<LinkInfo>).Value;

Related

Serializing/Deserializing an object that is derived from Java.Lang.Object throws exception (using System.Text.Json)

In one of my .net7-android project, I am trying to serialize an object using System.Text.Json. My object is derived from Java.Lang.Object. I am not intrested in serializing/deserializing the base class (Java.Lang.Object).
The exception I am getting is "Serialization and deserialization of 'System.Type' instances are not supported.". Anyone has any ideas how can it be fixed?
One of the public properties declared by Java.Lang.Object must (directly or indirectly) return an object of type System.Type, thereby causing the exception. Since you don't want to serialize any of these properties anyway, you could create a custom JsonTypeInfo modifier that excludes all properties declared by Java.Lang.Object.
First, define the following extension methods:
public static class JsonExtensions
{
public static Action<JsonTypeInfo> IgnorePropertiesDeclaredBy(Type declaringType)
=> (Action<JsonTypeInfo>) (typeInfo =>
{
if (typeInfo.Kind != JsonTypeInfoKind.Object || !declaringType.IsAssignableFrom(typeInfo.Type))
return;
foreach (var property in typeInfo.Properties)
if (property.GetDeclaringType() == declaringType)
property.ShouldSerialize = static (obj, value) => false;
});
public static Action<JsonTypeInfo> IgnorePropertiesDeclaredBy<TDeclaringType>() => IgnorePropertiesDeclaredBy(typeof(TDeclaringType));
public static Type? GetDeclaringType(this JsonPropertyInfo property) => (property.AttributeProvider as MemberInfo)?.DeclaringType;
}
And now you can use JsonExtensions.IgnorePropertiesDeclaredBy<Java.Lang.Object>() to omit all properties declared by Java.Lang.Object when serializing instances of derived types like so:
var options = new JsonSerializerOptions
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver
{
Modifiers = { JsonExtensions.IgnorePropertiesDeclaredBy<Java.Lang.Object>() },
},
// Add other options as required
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true,
};
var json = JsonSerializer.Serialize(myJavaObject, options);
Note that this will only suppress properties declared by some base type. Suppressing properties declared by an interface that the type implements is not implemented.
Demo fiddle using a mockup of Java.Lang.Object here: https://dotnetfiddle.net/8vNQS6.

Calling .filter() on a stream looses generic type

I have the following code. "Protectable" is an interface. My compiler gives the following error: "Incompatible types: Object cannot be converted to Collection"
When I remove the .filter line, everything works. Why does the compiler loose my type here?
Thanks,
Hannes
Collection<Protectable> requiredItems prefs.getConnectedProtectables(fuzDoc)
.stream()
.filter(protectable -> !protectable.itemVisibleForCurrentUser(fuzDoc))
.collect(Collectors.toList());
The variable prefs implements HasConnectedRights which is implemented as follows:
public interface HasConnectedRights {
public Collection<Protectable> getConnectedProtectables(FuzDocument doc);
}
The interface Protectable declares the method itemVisibleForCurrentUser like this:
default public boolean itemVisibleForCurrentUser(Docker<FuzDocument> doc) {
User user = UserCtrl.getCurrentUser(doc.getDoc());
return user == null || itemVisibleFor(user);
}

How to implement fluent api in ASP.NET MVC?

I want to implement fluent api to my mvc sites. I got the basics.
So implement object library such as:
public class UIElement{/*...*/}
public class ButtonBase : UIElement{/*...*/}
public class LinkButton : ButtonBase {/*...*/}
public static class Extensions
{
public static T UIElementMethod<T>(this T element, string title)
where T : UIElement
{
return element;
}
public static T ButtonBaseMethod<T>(this T element, string title)
where T : ButtonBase
{
return element;
}
public static T LinkButtonMethod<T>(this T element, string title)
where T : LinkButton
{
return element;
}
}
But how to use it in razor view without some flush method calling.
#Html.UIproject().LinkButton()
.UIElementMethod("asd")
.ButtonBaseMethod("asd")
.LinkButtonMethod("asd")
But it returns the name of the class. I tried to make an implicit operator to MvcHtmlString but it's not called.
Any idea how to achieve this. How to know it's the and of the chain. I like the way how the Kendo UI work.
Thanks,
Péter
Your UIElement classes need to implement the IHtmlString interface. This interface's ToHtmlString method gets called by Razor and should return an HTML-encoded string.
So I would implement this on the abscract base UIElement and create RenderHtml method which can be implemented by the concrete LinkButton, etc. classes:
public abstract class UIElement : IHtmlString
{
public string ToHtmlString()
{
return RenderHtml(); // This should return an HTML-encoded string.
}
public override string ToString()
{
return ToHtmlString();
}
protected abstract string RenderHtml();
}
If you check KendoUI in Reflector/JustDecompile/dotPeek in the WidgetBase class you will see the same pattern.
I haven't tried it, in this particular situation, but you might be able to use an implicit cast to convert from a fluent builder to the object you need (see this blog).

Structuremap constructor overloading

I have a command class that needs to have 2 constructors. However,
using structuremap it seems that I can only specify one constructor to
be used. I have solved the problem for now by subtyping the specific
command class, which each implementation implementing it's own
interface and constructor. Like the code below shows. The
ISelectCommand implements two separate interfaces for the
string constructor and the int constructor, just for the sake of
registering the two subtypes using structuremap.
However, I consider this a hack and I just wonder why is it not
possible for structuremap to resolve the constructor signature by the
type passed in as parameter for the constructor? Then I could register
the SelectProductCommand as an ISelectCommand and
instantiate it like:
ObjectFactury.With(10).Use>();
orObjectFactury.With("testproduct").Use>();
public class SelectProductCommand : ISelectCommand<IProduct>,
ICommand, IExecutable
{
private readonly Func<Product, Boolean> _selector;
private IEnumerable<IProduct> _resultList;
public SelectProductCommand(Func<Product, Boolean> selector)
{
_selector = selector;
}
public IEnumerable<IProduct> Result
{
get { return _resultList; }
}
public void Execute(GenFormDataContext context)
{
_resultList = GetProductRepository().Fetch(context,
_selector);
}
private Repository<IProduct, Product> GetProductRepository()
{
return ObjectFactory.GetInstance<Repository<IProduct,
Product>>();
}
}
public class SelectProductIntCommand: SelectProductCommand
{
public SelectProductIntCommand(Int32 id): base(x =>
x.ProductId == id) {}
}
public class SelectProductStringCommand: SelectProductCommand
{
public SelectProductStringCommand(String name): base(x =>
x.ProductName.Contains(name)) {}
}
P.s. I know how to tell structuremap what constructor map to use, but my again my question is if there is a way to have structuremap select the right constructor based on the parameter passed to the constructor (i.e. using regular method overloading).
The short answer is this post by the creator of Structuremap.
The long answer is regarding the structure you have in that piece of code. In my view, a command is by definition a "class" that does something to an "entity", i.e it modifies the class somehow. Think CreateNewProductCommand.
Here you are using commands for querying, if I'm not mistaken. You also have a bit of a separation of concern issue floating around here. The command posted defines what to do and how to do it, which is to much and you get that kind of Service location you're using in
private Repository<IProduct, Product> GetProductRepository()
{
return ObjectFactory.GetInstance<Repository<IProduct, Product>>();
}
The way I'd structure commands is to use CreateProductCommand as a data contract, i.e it only contains data such as product information.
Then you have a CreateProductCommandHandler which implements IHandles<CreateProductCommand> with a single method Handle or Execute. That way you get better separation of concern and testability.
As for the querying part, just use your repositores directly in your controller/presenter, alternatively use the Query Object pattern
I think I solved the problem using a small utility class. This class gets the concrete type from ObjectFactory and uses this type to construct the instance according to the parameters past into the factory method. Now on the 'client' side I use ObjectFactory to create an instance of CommandFactory. The implementation of CommandFactory is in another solution and thus the 'client solution' remains independent of the 'server' solution.
public class CommandFactory
{
public ICommand Create<T>()
{
return Create<T>(new object[] {});
}
public ICommand Create<T>(object arg1)
{
return Create<T>(new[] {arg1});
}
public ICommand Create<T>(object arg1, object arg2)
{
return Create<T>(new[] {arg1, arg2});
}
public ICommand Create<T>(object arg1, object arg2, object arg3)
{
return Create<T>(new[] {arg1, arg2, arg3});
}
public ICommand Create<T>(object[] arguments)
{
return (ICommand)Activator.CreateInstance(GetRegisteredType<T>(), arguments);
}
public static Type GetRegisteredType<T>()
{
return ObjectFactory.Model.DefaultTypeFor(typeof (T));
}
}

Doing interception with structuremap

I'm trying to do some attribute-based interception using structuremap but I'm struggling to tie up the last loose ends.
I have a custom Registry that scans my assemblies and in this Registry I have defined the following ITypeInterceptor whose purpose it is to match types decorated with the given attribute and then apply the interceptor if matched. The class is defined as such:
public class AttributeMatchTypeInterceptor<TAttribute, TInterceptor>
: TypeInterceptor
where TAttribute : Attribute
where TInterceptor : IInterceptor
{
private readonly ProxyGenerator m_proxyGeneration = new ProxyGenerator();
public object Process(object target, IContext context)
{
return m_proxyGeneration.CreateInterfaceProxyWithTarget(target, ObjectFactory.GetInstance<TInterceptor>());
}
public bool MatchesType(Type type)
{
return type.GetCustomAttributes(typeof (TAttribute), true).Length > 0;
}
}
//Usage
[Transactional]
public class OrderProcessor : IOrderProcessor{
}
...
public class MyRegistry : Registry{
public MyRegistry()
{
RegisterInterceptor(
new AttributeMatchTypeInterceptor<TransactionalAttribute, TransactionInterceptor>());
...
}
}
I'm using DynamicProxy from the Castle.Core to create the interceptors, but my problem is that the object returned from the CreateInterfaceProxyWithTarget(...) call does not implement the interface that triggered the creation of the target instance in structuremap (i.e IOrderProcessor in example above). I was hoping that the IContext parameter would reveal this interface, but I can only seem to get a hold of the concrete type (i.e. OrderProcessor in example above).
I'm looking for guidance on how to have this scenario work, either by calling the ProxyGenerator to return an instance that implements all interfaces as the target instance, by obtaining the requested interface from structuremap or through some other mechanism.
I actually got something working with a slight caveat so I'll just post this as the answer. The trick was to obtain the interface and pass that into the CreateInterfaceProxyWithTarget. My only problem was that I could not find a way to query the IContext about which interface it was currently resolving so I ended up just looking up the first interface on the target which worked for me. See code below
public class AttributeMatchTypeInterceptor<TAttribute, TInterceptor> :
TypeInterceptor
where TAttribute : Attribute
where TInterceptor : IInterceptor
{
private readonly ProxyGenerator m_proxyGeneration = new ProxyGenerator();
public object Process(object target, IContext context)
{
//NOTE: can't query IContext for actual interface
Type interfaceType = target.GetType().GetInterfaces().First();
return m_proxyGeneration.CreateInterfaceProxyWithTarget(
interfaceType,
target,
ObjectFactory.GetInstance<TInterceptor>());
}
public bool MatchesType(Type type)
{
return type.GetCustomAttributes(typeof (TAttribute), true).Length > 0;
}
}
Hope this helps someone

Resources