Is there any xaml serialization attribute that I can specify for a dependency property which actually is a collection (TextDecorationCollection)?
I want to use serialization for cloning a very large and complex object. Here a sample of the code, simplified:
There is a MyVisualObject, that contains a lot of properties, including a custom font, which I want to clone
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class Export : Attribute
{
}
public class MyVisualObject : DependencyObject
{
[Export]
public CustomFont Font
{
get { return (CustomFont)GetValue(FontProperty); }
set { SetValue(FontProperty, value); }
}
// Using a DependencyProperty as the backing store for Font. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FontProperty =
DependencyProperty.Register("Font", typeof(CustomFont), typeof(MyVisualObject));
public MyVisualObject()
{
this.Font = new CustomFont();
}
}
And the custom font is defined like this:
public class CustomFont : DependencyObject
{
public TextDecorationCollection Decorations
{
get { return (TextDecorationCollection)GetValue(DecorationsProperty); }
set { SetValue(DecorationsProperty, value); }
}
// Using a DependencyProperty as the backing store for TextDecorations. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DecorationsProperty =
DependencyProperty.Register("Decorations", typeof(TextDecorationCollection), typeof(CustomFont), new UIPropertyMetadata(new TextDecorationCollection()));
public CustomFont()
{
this.Decorations = System.Windows.TextDecorations.Underline;
}
}
THe deep clone method:
public static T DeepClone<T>(T from)
{
object clone = Activator.CreateInstance(from.GetType());
Type t = from.GetType();
System.Reflection.PropertyInfo[] pinf = t.GetProperties();
foreach (PropertyInfo p in pinf)
{
bool serialize = false;
foreach (object temp in p.GetCustomAttributes(true))
{
if (temp is Export)
{
serialize = true;
}
}
if (serialize)
{
string xaml = XamlWriter.Save(p.GetValue(from, null));
XmlReader rd = XmlReader.Create(new StringReader(xaml));
p.SetValue(clone, XamlReader.Load(rd), null);
}
}
return (T)clone;
}
The problem is that each time I initialize the Decorations as Underline
this.Decorations = System.Windows.TextDecorations.Underline;
the cloning process crashes with this error:'Add value to collection of type 'System.Windows.TextDecorationCollection' threw an exception.' Line number '1' and line position '213'.
As far as I found out, the serialization, which is this part
string xaml = XamlWriter.Save(p.GetValue(from, null));
returns an xaml which does not have the decorations set as a collection:
<CustomFont xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<CustomFont.Decorations>
<av:TextDecoration Location="Underline" />
</CustomFont.Decorations>
</CustomFont>
But the clone process would work if the xaml would be like this:
<CustomFont xmlns="clr-namespace:WpfApplication1;assembly=WpfApplication1" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<CustomFont.Decorations>
<av:TextDecorationCollection>
<av:TextDecoration Location="Underline" />
</av:TextDecorationCollection>
</CustomFont.Decorations>
</CustomFont>
I found a workaround, something with string replacements:
xaml = xaml.Replace("<CustomFont.Decorations><av:TextDecoration Location=\"Underline\" /></CustomFont.Decorations>", "<CustomFont.Decorations><av:TextDecorationCollection><av:TextDecoration Location=\"Underline\" /></av:TextDecorationCollection></CustomFont.Decorations>");
but I think it's really dirty, and I would apreciate it if you could provide a more clean solution (specifying an attribute for the Decorations property for example)
Have you tried applying the following attribute to the Decorations property:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
Related
This might be a duplicate. But I cannot find a solution to my Problem.
I have a class
public class MyResponse implements Serializable {
private boolean isSuccess;
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
}
Getters and setters are generated by Eclipse.
In another class, I set the value to true, and write it as a JSON string.
System.out.println(new ObjectMapper().writeValueAsString(myResponse));
In JSON, the key is coming as {"success": true}.
I want the key as isSuccess itself. Is Jackson using the setter method while serializing? How do I make the key the field name itself?
This is a slightly late answer, but may be useful for anyone else coming to this page.
A simple solution to changing the name that Jackson will use for when serializing to JSON is to use the #JsonProperty annotation, so your example would become:
public class MyResponse implements Serializable {
private boolean isSuccess;
#JsonProperty(value="isSuccess")
public boolean isSuccess() {
return isSuccess;
}
public void setSuccess(boolean isSuccess) {
this.isSuccess = isSuccess;
}
}
This would then be serialised to JSON as {"isSuccess":true}, but has the advantage of not having to modify your getter method name.
Note that in this case you could also write the annotation as #JsonProperty("isSuccess") as it only has the single value element
I recently ran into this issue and this is what I found. Jackson will inspect any class that you pass to it for getters and setters, and use those methods for serialization and deserialization. What follows "get", "is" and "set" in those methods will be used as the key for the JSON field ("isValid" for getIsValid and setIsValid).
public class JacksonExample {
private boolean isValid = false;
public boolean getIsValid() {
return isValid;
}
public void setIsValid(boolean isValid) {
this.isValid = isValid;
}
}
Similarly "isSuccess" will become "success", unless renamed to "isIsSuccess" or "getIsSuccess"
Read more here: http://www.citrine.io/blog/2015/5/20/jackson-json-processor
Using both annotations below, forces the output JSON to include is_xxx:
#get:JsonProperty("is_something")
#param:JsonProperty("is_something")
When you are using Kotlin and data classes:
data class Dto(
#get:JsonProperty("isSuccess") val isSuccess: Boolean
)
You might need to add #param:JsonProperty("isSuccess") if you are going to deserialize JSON as well.
EDIT: If you are using swagger-annotations to generate documentation, the property will be marked as readOnly when using #get:JsonProperty. In order to solve this, you can do:
#JsonAutoDetect(isGetterVisibility = JsonAutoDetect.Visibility.NONE)
data class Dto(
#field:JsonProperty(value = "isSuccess") val isSuccess: Boolean
)
You can configure your ObjectMapper as follows:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
{
if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
&& method.getName().startsWith("is")) {
return method.getName();
}
return super.nameForGetterMethod(config, method, defaultName);
}
});
I didn't want to mess with some custom naming strategies, nor re-creating some accessors.
The less code, the happier I am.
This did the trick for us :
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
#JsonIgnoreProperties({"success", "deleted"}) // <- Prevents serialization duplicates
public class MyResponse {
private String id;
private #JsonProperty("isSuccess") boolean isSuccess; // <- Forces field name
private #JsonProperty("isDeleted") boolean isDeleted;
}
Building upon Utkarsh's answer..
Getter names minus get/is is used as the JSON name.
public class Example{
private String radcliffe;
public getHarryPotter(){
return radcliffe;
}
}
is stored as { "harryPotter" : "whateverYouGaveHere" }
For Deserialization, Jackson checks against both the setter and the field name.
For the Json String { "word1" : "example" }, both the below are valid.
public class Example{
private String word1;
public setword2( String pqr){
this.word1 = pqr;
}
}
public class Example2{
private String word2;
public setWord1(String pqr){
this.word2 = pqr ;
}
}
A more interesting question is which order Jackson considers for deserialization. If i try to deserialize { "word1" : "myName" } with
public class Example3{
private String word1;
private String word2;
public setWord1( String parameter){
this.word2 = parameter ;
}
}
I did not test the above case, but it would be interesting to see the values of word1 & word2 ...
Note: I used drastically different names to emphasize which fields are required to be same.
You can change primitive boolean to java.lang.Boolean (+ use #JsonPropery)
#JsonProperty("isA")
private Boolean isA = false;
public Boolean getA() {
return this.isA;
}
public void setA(Boolean a) {
this.isA = a;
}
Worked excellent for me.
If you are interested in handling 3rd party classes not under your control (like #edmundpie mentioned in a comment) then you add Mixin classes to your ObjectMapper where the property/field names should match the ones from your 3rd party class:
public class MyStack32270422 {
public static void main(String[] args) {
ObjectMapper om3rdParty = new ObjectMapper();
om3rdParty .addMixIn(My3rdPartyResponse.class, MixinMyResponse.class);
// add further mixins if required
String jsonString = om3rdParty.writeValueAsString(new My3rdPartyResponse());
System.out.println(jsonString);
}
}
class MixinMyResponse {
// add all jackson annotations here you want to be used when handling My3rdPartyResponse classes
#JsonProperty("isSuccess")
private boolean isSuccess;
}
class My3rdPartyResponse{
private boolean isSuccess = true;
// getter and setter here if desired
}
Basically you add all your Jackson annotations to your Mixin classes as if you would own the class. In my opinion quite a nice solution as you don't have to mess around with checking method names starting with "is.." and so on.
there is another method for this problem.
just define a new sub-class extends PropertyNamingStrategy and pass it to ObjectMapper instance.
here is a code snippet may be help more:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
String input = defaultName;
if(method.getName().startsWith("is")){
input = method.getName();
}
//copy from LowerCaseWithUnderscoresStrategy
if (input == null) return input; // garbage in, garbage out
int length = input.length();
StringBuilder result = new StringBuilder(length * 2);
int resultLength = 0;
boolean wasPrevTranslated = false;
for (int i = 0; i < length; i++)
{
char c = input.charAt(i);
if (i > 0 || c != '_') // skip first starting underscore
{
if (Character.isUpperCase(c))
{
if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_')
{
result.append('_');
resultLength++;
}
c = Character.toLowerCase(c);
wasPrevTranslated = true;
}
else
{
wasPrevTranslated = false;
}
result.append(c);
resultLength++;
}
}
return resultLength > 0 ? result.toString() : input;
}
});
The accepted answer won't work for my case.
In my case, the class is not owned by me. The problematic class comes from 3rd party dependencies, so I can't just add #JsonProperty annotation in it.
To solve it, inspired by #burak answer above, I created a custom PropertyNamingStrategy as follow:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy() {
#Override
public String nameForSetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
{
if (method.getParameterCount() == 1 &&
(method.getRawParameterType(0) == Boolean.class || method.getRawParameterType(0) == boolean.class) &&
method.getName().startsWith("set")) {
Class<?> containingClass = method.getDeclaringClass();
String potentialFieldName = "is" + method.getName().substring(3);
try {
containingClass.getDeclaredField(potentialFieldName);
return potentialFieldName;
} catch (NoSuchFieldException e) {
// do nothing and fall through
}
}
return super.nameForSetterMethod(config, method, defaultName);
}
#Override
public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName)
{
if(method.hasReturnType() && (method.getRawReturnType() == Boolean.class || method.getRawReturnType() == boolean.class)
&& method.getName().startsWith("is")) {
Class<?> containingClass = method.getDeclaringClass();
String potentialFieldName = method.getName();
try {
containingClass.getDeclaredField(potentialFieldName);
return potentialFieldName;
} catch (NoSuchFieldException e) {
// do nothing and fall through
}
}
return super.nameForGetterMethod(config, method, defaultName);
}
});
Basically what this does is, before serializing and deserializing, it checks in the target/source class which property name is present in the class, whether it is isEnabled or enabled property.
Based on that, the mapper will serialize and deserialize to the property name that is exist.
i'm developing with uwp and i've a problem with data binding. I have a listView that i fill with a custom panel elements called PlaylistLeftOption class. This class inherit Panel class attributes that inherit FrameworkElement class attribute and its methods so i have a SetBinding method avaible.
Now i'm trying to bind the height value (it's equal to other elements) so i created a static attribute, called PerformanceItemHeight, in other extern singleton class.
since i need to fill listview dinamically i'm trying to bind the value inside the constructor but it don't work.
This is the code inside constructor:
public PlaylistLeftOption()
{
mainGrid.Background = new SolidColorBrush(Colors.Red);
mainGrid.BorderBrush = new SolidColorBrush(Colors.Black);
mainGrid.BorderThickness = new Thickness(0.5,0.25,0.5,0.25);
WidthVal = 200;
HeightVal = 50;
var myBinding = new Binding();
myBinding.Source = PerformanceLayout.Instance.PerformanceItemHeight;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myBinding.Mode = BindingMode.TwoWay;
SetBinding(HeightValProperty, myBinding);
Children.Add(mainGrid);
}
And this is the property:
public static readonly DependencyProperty HeightValProperty = DependencyProperty.Register(
"HeightVal",
typeof(double),
typeof(PlaylistLeftOption),
new PropertyMetadata(50)
);
public double HeightVal
{
get => (double)GetValue(HeightValProperty);
set
{
SetValue(HeightValProperty, value);
Height = HeightVal;
mainGrid.Height = HeightVal;
globalSize.Height = HeightVal;
}
}
This is the code for PerformanceItemHeight:
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private double _performanceItemHeight = 50;
public double PerformanceItemHeight {
get => _performanceItemHeight;
set {
_performanceItemHeight = value;
this.OnPropertyChanged();
}
}
Why does via xaml it works?
i tryied to add PlaylistLeftOption item inside listview via xaml and it's ok!
thank you
By testing, the binding of HeightVal works in XAML and the binding of HeightVal does not work in code-behind. You could see the reason in the section Implementing the wrapper of the document Custom dependency properties which says that your wrapper implementations should perform only the GetValue and SetValue operations. Otherwise, you'll get different behavior when your property is set via XAML versus when it is set via code.
You could add a property-changed callback method to notify the changes of HeightVal actively.
For example:
public static readonly DependencyProperty HeightValProperty = DependencyProperty.Register(
"HeightVal",
typeof(double),
typeof(PlaylistLeftOption),
new PropertyMetadata(100, new PropertyChangedCallback(OnHeightValChanged))
);
private static void OnHeightValChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PlaylistLeftOption playlistLeftOption = d as PlaylistLeftOption;
if(playlistLeftOption != null)
{
var height = (Double)e.NewValue;
playlistLeftOption.HeightVal = height;
}
}
And change the binging code like this:
var myBinding = new Binding();
myBinding.Source = PerformanceLayout.Instance;
myBinding.Path = new PropertyPath("PerformanceItemHeight");
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
myBinding.Mode = BindingMode.TwoWay;
SetBinding(HeightValProperty, myBinding);
How can I bind InitializerForXXX (non-generic implementation) to IInitializer<XXX> (generic interface) using Ninject Conventions so that requests for an IInitializer<T> resolve a non-generic implementation whose name starts with InitializerFor and end with typeof(T).Name like:
initializerFactory.CreateFor<Blue>(); //resolves InitializerOfBlue
initializerFactory.CreateFor<ShadeOfBlue>(); //resolves InitializerOfShadeOfBlue
where no non-abstract class directly implement IInitializer<T>, and some implementations inherit from other implementations:
InitializerForShadeOfBlue inherits from InitializerForBlue
InitializerForBlue inherits from abstract Initializer<Blue>
abstract Initializer<T> directly implements IInitializer<T>
I'm hoping I can use a .EndsWith(typeof(T).Name) for a given IInitializer<T> convention I can use, because there are literally hundreds of initializers in the ShadeOfxxx vein. If I have to map all of them, I'm better off finding a way to resolve with reflection at runtime.
Given the following:
UPDATE: bindings with custom binding generator (see my answer below for implementation)
void Bootstrap(IBindingRoot kernel)
{
kernel.Bind<IInitializerFactory>()
.To<InitializerFactory>()
.InSingletonScope();
kernel.Bind(scanner =>
scanner.FromThisAssembly().SelectAllClasses()
.WhichAreNotGeneric()
.InheritedFrom(typeof(IComplexContent))
.BindAllInterfaces());
kernel.Bind(scanner =>
scanner.FromThisAssembly().SelectAllClasses()
.WhichAreNotGeneric()
.InheritedFrom(typeof(IInitializer<>))
.BindWith<FirstTypeParameterNameMatchesEndOfBoundClassNameGenerator>());
}
main method
void Main(IEnumerable<string> values)
{
// setup bindings
var kernel = new StandardKernel();
Bootstrap(kernel);
IInitializerFactory initializerFactory =
kernel.Get<IInitializerFactory>();
IInitializer<ShadeOfBlueComplexContent> initializer =
initializerFactory.CreateFor<ShadeOfBlueComplexContent>();
initializer.Initialize(values);
}
initializer factory
interface IInitializerFactory
{
IInitializer<T> CreateFor<T>() where T : class, IComplexContent, new();
}
class InitializerFactory : IInitializerFactory
{
public IInitializer<T> CreateFor<T>() where T : class, IComplexContent, new()
{
return MagicallyGetInitializer<T>();
}
//behind the curtain, whirring noises are heard as 't' is resolved...
private static IInitializer<T> MagicallyGetInitializer<T>()
where T : class, IComplexContent, new()
{
IInitializer<T> i = null;
return i;
}
}
initializers
interface IInitializer<out T> where T : IComplexContent
{
T Initialize(IEnumerable<string> values);
}
abstract class Initializer<T> : IInitializer<T> where T : IComplexContent
{
public abstract T Initialize(IEnumerable<string> values);
}
class InitializerOfBlue : Initializer<Blue>
{
private readonly Blue _content;
public InitializerOfBlue(Blue content) {_content = content;}
public override Blue Initialize(IEnumerable<string> values)
{
_content.BlueSpecificProperty = values.ElementAt(0);
//... populate other blue-specific properties like this
return _content;
}
}
class InitializerOfShadeOfBlue : InitializerOfBlue
{
public InitializerOfShadeOfBlue(ShadeOfBlue content) : base(content){}
}
content models
interface IComplexContent
{
string OneBasicProperty { get; set; }
// other properties are specific to implementation
string UniqueOperation();
}
abstract class BaseComplexContent : IComplexContent
{
public string OneBasicProperty { get; set; }
public abstract string UniqueOperation();
}
class Blue : BaseComplexContent
{
// initializer sets this
public string PropertyForAllKindsOfBlue { get; set; }
// initializer doesn't interact with this
public override string UniqueOperation() {return "I'm plain.";}
}
class ShadeOfBlue : Blue
{
// initializer doesn't interact with this
public override string UniqueOperation() {return "I'm fabulous!";}
}
You are over specifying the class selection
kernel.Bind(scanner =>
scanner.FromThisAssembly().SelectAllClasses()
.WhichAreNotGeneric()
.InheritedFrom(typeof (IInitializer<>))
This is already enough. What you need to do though is to add a custom Binding Generator. That selects IInitializer<Blue> for InitializerForBlue and IInitializer<ShadeOfBlue> for InitializerForShadeOfBlue
https://github.com/ninject/ninject.extensions.conventions/wiki/Projecting-Services-to-Bind
BEGIN SOLUTION CANDIDATE - custom binding generator:
custom binding generator
Thanks for the advice, #RemoGloor and #RubenBartelink. I'm stumped though - the problem is that I wind up binding the IInitializer<Blue> to InitializerOfShadeOfBlue. I need to be able to somehow change the generic type argument from Blue to ShadeOfBlue in the IInitializer<Blue> binding candidate, since IInitializer<ShadeOfBlue> is what will be requested from the factory method at runtime.
Is there a way to modify the generic type argument list of the binding candidate? Or am I barking up the wrong implementation? Any edit suggestions to my OP or this answer are appreciated.
/// <summary>Creates bindings on open generic types where bound implementations'
/// names end with the name of the generic type argument</summary>
public class FirstTypeParameterNameMatchesEndOfBoundClassNameGenerator : IBindingGenerator
{
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type == null) throw new ArgumentNullException("type");
if (bindingRoot == null) throw new ArgumentNullException("bindingRoot");
// only consider concrete, non-abstract classes
if (type.IsInterface || type.IsAbstract) yield break;
var bindingType = GetBindingType(type);
if (bindingType != null)
yield return bindingRoot.Bind(bindingType).To(type);
// ARGH! bindingType == IInitializer`1[[Blue]] but I want
// IInitializer`1[[ShadeOfBlue]] for type == ShadeOfBlue
}
private static Type GetBindingType(Type type)
{
Type goodMatch = null;
foreach (var candidate in type.GetInterfaces())
{
// skip non-generic interfaces
if (!candidate.IsGenericType) continue;
// assumption: using argument in first position
var firstArg = candidate.GetGenericArguments().First();
if (!type.Name.EndsWith(firstArg.Name)) continue;
// IInitializer<XXX> matches InitializerOfXXX
goodMatch = candidate;
break;
}
if (goodMatch == null)
{
// if no match on interfaces, walk through the ancestor types
foreach (var candidate in type.GetAllAncestors())
{
goodMatch = GetBindingType(candidate);
if (goodMatch != null) break;
}
}
return goodMatch;
}
Type Extension helper
public static class TypeExtensions
{
// returns all ancestor types starting with the parent
public static IEnumerable<Type> GetAllAncestors(this Type type)
{
for (var current = type.BaseType; current != null; current = current.BaseType)
yield return current;
}
}
END SOLUTION CANDIDATE - custom binding generator
I found this question difficult to express (particularly in title form), so please bear with me.
I have an application that I am continually modifying to do different things. It seems like MEF might be a good way to manage the different pieces of functionality. Broadly speaking, there are three sections of the application that form a pipeline of sorts:
Acquisition
Transformation
Expression
In it's simplest form, I can express each of these stages as an interface (IAcquisition etc). The problems start when I want to use acquisition components that provides richer data than standard. I want to design modules that use this richer data, but I can't rely on it being there.
I could, of course, add all of the data to the interface specification. I could deal with poorer data sources by throwing an exception or returning a null value. This seems a long way from ideal.
I'd prefer to do the MEF binding in three stages, such that modules are offered to the user only if they are compatible with those selected previously.
So my question: Can I specify metadata which restricts the set of available imports?
An example:
Acquision1 offers BasicData only
Acquision2 offers BasicData and AdvancedData
Transformation1 requires BasicData
Transformation2 requires BasicData and AdvancedData
Acquisition module is selected first.
If Acquisition1 is selected, don't offer Transformation 2, otherwise offer both.
Is this possible? If so, how?
Your question suggests a structure like this:
public class BasicData
{
public string Basic { get; set; } // example data
}
public class AdvancedData : BasicData
{
public string Advanced { get; set; } // example data
}
Now you have your acquisition, transformation and expression components. You want to be able to deal with different kinds of data, so they're generic:
public interface IAcquisition<out TDataKind>
{
TDataKind Acquire();
}
public interface ITransformation<TDataKind>
{
TDataKind Transform(TDataKind data);
}
public interface IExpression<in TDataKind>
{
void Express(TDataKind data);
}
And now you want to build a pipeline out of them that looks like this:
IExpression.Express(ITransformation.Transform(IAcquisition.Acquire));
So let's start building a pipeline builder:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using System.Linq.Expressions;
// namespace ...
public static class PipelineBuidler
{
private static readonly string AcquisitionIdentity =
AttributedModelServices.GetTypeIdentity(typeof(IAcquisition<>));
private static readonly string TransformationIdentity =
AttributedModelServices.GetTypeIdentity(typeof(ITransformation<>));
private static readonly string ExpressionIdentity =
AttributedModelServices.GetTypeIdentity(typeof(IExpression<>));
public static Action BuildPipeline(ComposablePartCatalog catalog,
Func<IEnumerable<string>, int> acquisitionSelector,
Func<IEnumerable<string>, int> transformationSelector,
Func<IEnumerable<string>, int> expressionSelector)
{
var container = new CompositionContainer(catalog);
The class holds MEF type identities for your three contract interfaces. We'll need those later to identify the correct exports. Our BuildPipeline method returns an Action. That is going to be the pipeline, so we can just do pipeline(). It takes a ComposablePartCatalog and three Funcs (to select an export). That way, we can keep all the dirty work inside this class. Then we start by creating a CompositionContainer.
Now we have to build ImportDefinitions, first for the acquisition component:
var aImportDef = new ImportDefinition(def => (def.ContractName == AcquisitionIdentity), null, ImportCardinality.ZeroOrMore, true, false);
This ImportDefinition simply filters out all exports of the IAcquisition<> interface. Now we can give it to the container:
var aExports = container.GetExports(aImportDef).ToArray();
aExports now holds all IAcquisition<> exports in the catalog. So let's run the selector on this:
var selectedAExport = aExports[acquisitionSelector(aExports.Select(export => export.Metadata["Name"] as string))];
And there we have our acquisition component:
var acquisition = selectedAExport.Value;
var acquisitionDataKind = (Type)selectedAExport.Metadata["DataKind"];
Now we're going to do the same for the transformation and the expression components, but with one slight difference: The ImportDefinition is going to ensure that each component can handle the output of the previous component.
var tImportDef = new ImportDefinition(def => (def.ContractName == TransformationIdentity) && ((Type)def.Metadata["DataKind"]).IsAssignableFrom(acquisitionDataKind),
null, ImportCardinality.ZeroOrMore, true, false);
var tExports = container.GetExports(tImportDef).ToArray();
var selectedTExport = tExports[transformationSelector(tExports.Select(export => export.Metadata["Name"] as string))];
var transformation = selectedTExport.Value;
var transformationDataKind = (Type)selectedTExport.Metadata["DataKind"];
var eImportDef = new ImportDefinition(def => (def.ContractName == ExpressionIdentity) && ((Type)def.Metadata["DataKind"]).IsAssignableFrom(transformationDataKind),
null, ImportCardinality.ZeroOrMore, true, false);
var eExports = container.GetExports(eImportDef).ToArray();
var selectedEExport = eExports[expressionSelector(eExports.Select(export => export.Metadata["Name"] as string))];
var expression = selectedEExport.Value;
var expressionDataKind = (Type)selectedEExport.Metadata["DataKind"];
And now we can wire it all up in an expression tree:
var acquired = Expression.Call(Expression.Constant(acquisition), typeof(IAcquisition<>).MakeGenericType(acquisitionDataKind).GetMethod("Acquire"));
var transformed = Expression.Call(Expression.Constant(transformation), typeof(ITransformation<>).MakeGenericType(transformationDataKind).GetMethod("Transform"), acquired);
var expressed = Expression.Call(Expression.Constant(expression), typeof(IExpression<>).MakeGenericType(expressionDataKind).GetMethod("Express"), transformed);
return Expression.Lambda<Action>(expressed).Compile();
}
}
And that's it! A simple example application would look like this:
[Export(typeof(IAcquisition<>))]
[ExportMetadata("DataKind", typeof(BasicData))]
[ExportMetadata("Name", "Basic acquisition")]
public class Acquisition1 : IAcquisition<BasicData>
{
public BasicData Acquire()
{
return new BasicData { Basic = "Acquisition1" };
}
}
[Export(typeof(IAcquisition<>))]
[ExportMetadata("DataKind", typeof(AdvancedData))]
[ExportMetadata("Name", "Advanced acquisition")]
public class Acquisition2 : IAcquisition<AdvancedData>
{
public AdvancedData Acquire()
{
return new AdvancedData { Advanced = "Acquisition2A", Basic = "Acquisition2B" };
}
}
[Export(typeof(ITransformation<>))]
[ExportMetadata("DataKind", typeof(BasicData))]
[ExportMetadata("Name", "Basic transformation")]
public class Transformation1 : ITransformation<BasicData>
{
public BasicData Transform(BasicData data)
{
data.Basic += " - Transformed1";
return data;
}
}
[Export(typeof(ITransformation<>))]
[ExportMetadata("DataKind", typeof(AdvancedData))]
[ExportMetadata("Name", "Advanced transformation")]
public class Transformation2 : ITransformation<AdvancedData>
{
public AdvancedData Transform(AdvancedData data)
{
data.Basic += " - Transformed2";
data.Advanced += " - Transformed2";
return data;
}
}
[Export(typeof(IExpression<>))]
[ExportMetadata("DataKind", typeof(BasicData))]
[ExportMetadata("Name", "Basic expression")]
public class Expression1 : IExpression<BasicData>
{
public void Express(BasicData data)
{
Console.WriteLine("Expression1: {0}", data.Basic);
}
}
[Export(typeof(IExpression<>))]
[ExportMetadata("DataKind", typeof(AdvancedData))]
[ExportMetadata("Name", "Advanced expression")]
public class Expression2 : IExpression<AdvancedData>
{
public void Express(AdvancedData data)
{
Console.WriteLine("Expression2: ({0}) - ({1})", data.Basic, data.Advanced);
}
}
class Program
{
static void Main(string[] args)
{
var pipeline = PipelineBuidler.BuildPipeline(new AssemblyCatalog(typeof(Program).Assembly), StringSelector, StringSelector, StringSelector);
pipeline();
}
static int StringSelector(IEnumerable<string> strings)
{
int i = 0;
foreach (var item in strings)
Console.WriteLine("[{0}] {1}", i++, item);
return int.Parse(Console.ReadLine());
}
}
Is anybody using JSON.NET with nHibernate? I notice that I am getting errors when I try to load a class with child collections.
I was facing the same problem so I tried to use #Liedman's code but the GetSerializableMembers() was never get called for the proxied reference.
I found another method to override:
public class NHibernateContractResolver : DefaultContractResolver
{
protected override JsonContract CreateContract(Type objectType)
{
if (typeof(NHibernate.Proxy.INHibernateProxy).IsAssignableFrom(objectType))
return base.CreateContract(objectType.BaseType);
else
return base.CreateContract(objectType);
}
}
We had this exact problem, which was solved with inspiration from Handcraftsman's response here.
The problem arises from JSON.NET being confused about how to serialize NHibernate's proxy classes. Solution: serialize the proxy instances like their base class.
A simplified version of Handcraftsman's code goes like this:
public class NHibernateContractResolver : DefaultContractResolver {
protected override List<MemberInfo> GetSerializableMembers(Type objectType) {
if (typeof(INHibernateProxy).IsAssignableFrom(objectType)) {
return base.GetSerializableMembers(objectType.BaseType);
} else {
return base.GetSerializableMembers(objectType);
}
}
}
IMHO, this code has the advantage of still relying on JSON.NET's default behaviour regarding custom attributes, etc. (and the code is a lot shorter!).
It is used like this
var serializer = new JsonSerializer{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new NHibernateContractResolver()
};
StringWriter stringWriter = new StringWriter();
JsonWriter jsonWriter = new Newtonsoft.Json.JsonTextWriter(stringWriter);
serializer.Serialize(jsonWriter, objectToSerialize);
string serializedObject = stringWriter.ToString();
Note: This code was written for and used with NHibernate 2.1. As some commenters have pointed out, it doesn't work out of the box with later versions of NHibernate, you will have to make some adjustments. I will try to update the code if I ever have to do it with later versions of NHibernate.
I use NHibernate with Json.NET and noticed that I was getting inexplicable "__interceptors" properties in my serialized objects. A google search turned up this excellent solution by Lee Henson which I adapted to work with Json.NET 3.5 Release 5 as follows.
public class NHibernateContractResolver : DefaultContractResolver
{
private static readonly MemberInfo[] NHibernateProxyInterfaceMembers = typeof(INHibernateProxy).GetMembers();
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
var members = base.GetSerializableMembers(objectType);
members.RemoveAll(memberInfo =>
(IsMemberPartOfNHibernateProxyInterface(memberInfo)) ||
(IsMemberDynamicProxyMixin(memberInfo)) ||
(IsMemberMarkedWithIgnoreAttribute(memberInfo, objectType)) ||
(IsMemberInheritedFromProxySuperclass(memberInfo, objectType)));
var actualMemberInfos = new List<MemberInfo>();
foreach (var memberInfo in members)
{
var infos = memberInfo.DeclaringType.BaseType.GetMember(memberInfo.Name);
actualMemberInfos.Add(infos.Length == 0 ? memberInfo : infos[0]);
}
return actualMemberInfos;
}
private static bool IsMemberDynamicProxyMixin(MemberInfo memberInfo)
{
return memberInfo.Name == "__interceptors";
}
private static bool IsMemberInheritedFromProxySuperclass(MemberInfo memberInfo, Type objectType)
{
return memberInfo.DeclaringType.Assembly == typeof(INHibernateProxy).Assembly;
}
private static bool IsMemberMarkedWithIgnoreAttribute(MemberInfo memberInfo, Type objectType)
{
var infos = typeof(INHibernateProxy).IsAssignableFrom(objectType)
? objectType.BaseType.GetMember(memberInfo.Name)
: objectType.GetMember(memberInfo.Name);
return infos[0].GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Length > 0;
}
private static bool IsMemberPartOfNHibernateProxyInterface(MemberInfo memberInfo)
{
return Array.Exists(NHibernateProxyInterfaceMembers, mi => memberInfo.Name == mi.Name);
}
}
To use it just put an instance in the ContractResolver property of your JsonSerializer. The circular dependency problem noted by jishi can be resolved by setting the ReferenceLoopHandling property to ReferenceLoopHandling.Ignore . Here's an extension method that can be used to serialize objects using Json.Net
public static void SerializeToJsonFile<T>(this T itemToSerialize, string filePath)
{
using (StreamWriter streamWriter = new StreamWriter(filePath))
{
using (JsonWriter jsonWriter = new JsonTextWriter(streamWriter))
{
jsonWriter.Formatting = Formatting.Indented;
JsonSerializer serializer = new JsonSerializer
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new NHibernateContractResolver(),
};
serializer.Serialize(jsonWriter, itemToSerialize);
}
}
}
Are you getting a circular dependancy-error? How do you ignore objects from serialization?
Since lazy loading generates a proxy-objects, any attributes your class-members have will be lost. I ran into the same issue with Newtonsoft JSON-serializer, since the proxy-object didn't have the [JsonIgnore] attributes anymore.
You will probably want to eager load most of the object so that it can be serialized:
ICriteria ic = _session.CreateCriteria(typeof(Person));
ic.Add(Restrictions.Eq("Id", id));
if (fetchEager)
{
ic.SetFetchMode("Person", FetchMode.Eager);
}
A nice way to do this is to add a bool to the constructor (bool isFetchEager) of your data provider method.
I'd say this is a design problem in my opinion. Because NH makes connections to the database underneath all and has proxies in the middle, it is not good for the transparency of your application to serialize them directly (and as you can see Json.NET does not like them at all).
You should not serialize the entities themselves, but you should convert them into "view" objects or POCO or DTO objects (whatever you want to call them) and then serialize these.
The difference is that while NH entity may have proxies, lazy attributes, etc. View objects are simple objects with only primitives which are serializable by default.
How to manage FKs?
My personal rule is:
Entity level: Person class and with a Gender class associated
View level: Person view with GenderId and GenderName properties.
This means that you need to expand your properties into primitives when converting to view objects. This way also your json objects are simpler and easier to handle.
When you need to push the changes to the DB, in my case I use AutoMapper and do a ValueResolver class which can convert your new Guid to the Gender object.
UPDATE: Check http://blog.andrewawhitaker.com/blog/2014/06/19/queryover-series-part-4-transforming/ for a way to get the view directly (AliasToBean) from NH. This would be a boost in the DB side.
The problem can happen when NHibernate wraps the nested collection properties in a PersistentGenericBag<> type.
The GetSerializableMembers and CreateContract overrides cannot detect that these nested collection properties are "proxied". One way to resolve this is to override the CreateProperty method. The trick is to get the value from the property using reflection and test whether the type is of PersistentGenericBag. This method also has the ability to filter any properties that generated exceptions.
public class NHibernateContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
property.ShouldSerialize = instance =>
{
try
{
PropertyInfo prop = (PropertyInfo)member;
if (prop.CanRead)
{
var value = prop.GetValue(instance, null);
if (value != null && typeof(NHibernate.Collection.Generic.PersistentGenericBag<>).IsSubclassOfRawGeneric(value.GetType()))
return false;
return true;
}
}
catch
{ }
return false;
};
return property;
}
}
The IsSubclassOfRawGeneric extension used above:
public static class TypeExtensions
{
public static bool IsSubclassOfRawGeneric(this Type generic, Type? toCheck)
{
while (toCheck != null && toCheck != typeof(object))
{
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur)
{
return true;
}
toCheck = toCheck?.BaseType;
}
return false;
}
}
If you serialize objects that contain NHibernate proxy classes you might end up downloading the whole database, because once the property is accessed NHibernate would trigger a request to the database.
I've just implemented a Unit of Work for NHibernate: NHUnit that fixes two of the most annoying issues from NHibernate: proxy classes and cartesian product when using fetch.
How would you use this?
var customer = await _dbContext.Customers.Get(customerId) //returns a wrapper to configure the query
.Include(c => c.Addresses.Single().Country, //include Addresses and Country
c => c.PhoneNumbers.Single().PhoneNumberType) //include all PhoneNumbers with PhoneNumberType
.Unproxy() //instructs the framework to strip all the proxy classes when the Value is returned
.Deferred() //instructs the framework to delay execution (future)
.ValueAsync(token); //this is where all deferred queries get executed
The above code is basically configuring a query: return a customer by id with multiple child objects which should be executed with other queries (futures) and the returned result should be stripped of NHibernate proxies. The query gets executed when ValueAsync is called.
NHUnit determines if it should do join with the main query, create new future queries or make use of batch fetch.
There is a simple example project on Github to show you how to use NHUnit package. If others are interested in this project I will invest more time to make it better.
This is what I use:
Have a marker interface and inherit it on your entities, e.g. in my case empty IEntity.
We will use the marker interface to detect NHibernate entity types in the contract resolver.
public class CustomerEntity : IEntity { ... }
Create a custom contract resolver for JSON.NET
public class NHibernateProxyJsonValueProvider : IValueProvider {
private readonly IValueProvider _valueProvider;
public NHibernateProxyJsonValueProvider(IValueProvider valueProvider)
{
_valueProvider = valueProvider;
}
public void SetValue(object target, object value)
{
_valueProvider.SetValue(target, value);
}
private static (bool isProxy, bool isInitialized) GetProxy(object proxy)
{
// this is pretty much what NHibernateUtil.IsInitialized() does.
switch (proxy)
{
case INHibernateProxy hibernateProxy:
return (true, !hibernateProxy.HibernateLazyInitializer.IsUninitialized);
case ILazyInitializedCollection initializedCollection:
return (true, initializedCollection.WasInitialized);
case IPersistentCollection persistentCollection:
return (true, persistentCollection.WasInitialized);
default:
return (false, false);
}
}
public object GetValue(object target)
{
object value = _valueProvider.GetValue(target);
(bool isProxy, bool isInitialized) = GetProxy(value);
if (isProxy)
{
if (isInitialized)
{
return value;
}
if (value is IEnumerable)
{
return Enumerable.Empty<object>();
}
return null;
}
return value;
}
}
public class NHibernateContractResolver : CamelCasePropertyNamesContractResolver {
protected override JsonContract CreateContract(Type objectType)
{
if (objectType.IsAssignableTo(typeof(IEntity)))
{
return base.CreateObjectContract(objectType);
}
return base.CreateContract(objectType);
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
property.ValueProvider = new NHibernateProxyJsonValueProvider(property.ValueProvider);
return property;
}
}
Normal uninitialized lazy loaded properties will result in null in the json output.
Collection uninitialized lazy loaded properties will result in an [] empty array in json.
So for a lazy loaded property to appear in the json output you need to eagerly load it in the query or in code before serialization.
Usage:
JsonConvert.SerializeObject(entityToSerialize, new JsonSerializerSettings() {
ContractResolver = new NHibernateContractResolver()
});
Or globally in in ASP.NET Core Startup class
services.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = new NHibernateContractResolver();
});
Using:
NET 5.0
NHibernate 5.3.8
JSON.NET latest via ASP.NET Core