how to map from JaxbElement<X> to JaxbElement<Y> with MapStruct - jaxb

I was going to create an issue on github, but the issue template says I'd rather discuss it here first, so here we go:
I am trying to use Mapstruct to generate mappings from one WSDL-generated set of entities to another. However, without adding a "default" method (manual mapping) it does not work ! That seems to be strange, as I would expect this kind of mapping should not be difficult for Mapstruct. repro case is here: https://github.com/62mkv/wsdl-mapstruct-repro-case
the gist of the code is here:
#Mapper(uses = {
org.system.wsdl.legacy.ObjectFactory.class
})
public interface WsMapper {
org.system.wsdl.legacy.SellGarlicRequest fromCloud(org.system.wsdl.cloud.SellGarlicRequest request);
}
this code above will fail to compile, with such message:
Can't map property "javax.xml.bind.JAXBElement inputParameters" to "javax.xml.bind.JAXBElement inputParameters". Consider to declare/implement a mapping method: "javax.xml.bind.JAXBElement map(javax.xml.bind.JAXBElement value)". org.system.wsdl.legacy.SellGarlicRequest fromCloud(org.system.wsdl.cloud.SellGarlicRequest request);
basically, mapping would go as follows: EntityNew -> JaxbElement -> FieldNew -> FieldOld -> JaxbElement -> EntityOld
as I've read here (https://stackoverflow.com/a/46015381/2583044), mapping from JaxbElement to T is trivial for MapStruct, and to map from T to JaxbElement one has to use "uses" annotation and provide ObjectFactory.class, which I do; however... this seems to not be enough.
if I add these two methods, code compiles good:
org.system.wsdl.legacy.GarlicParameterCollection garlicParameterCollectionToGarlicParameterCollection(org.system.wsdl.cloud.GarlicParameterCollection collection);
default JAXBElement<org.system.wsdl.legacy.GarlicParameterCollection> garlicParameterCollectionToGarlicParameterCollection(JAXBElement<org.system.wsdl.cloud.GarlicParameterCollection> parameterCollectionJAXBElement) {
return new org.system.wsdl.legacy.ObjectFactory().createSellGarlicRequestInputParameters(
this.garlicParameterCollectionToGarlicParameterCollection(parameterCollectionJAXBElement.getValue())
);
}
is it a potential issue in mapstruct or I just don't know how to cook it well?

The problem is that MapStruct sees your object factory method (with argument) as a mapping method. So, it delivers a target, but it has a source as well. If you realise this, then the mapping suddenly is not symmetrical (as it initially appears).
The simple solution is to instruct MapStruct how to handle this.
So: try this:
#Mapper(uses = {
org.system.wsdl.legacy.ObjectFactory.class
})
public interface WsMapper {
org.system.wsdl.legacy.GarlicParameterCollection garlicParameterCollectionToGarlicParameterCollection(org.system.wsdl.cloud.GarlicParameterCollection collection);
#Mapping( target = "inputParameters", source = "inputParameters.value") // this instructs MapStruct to use value of the source JAXBElement (for which it has an object factory method) instead of trying to map JAXBElement to JAXBElement.
org.system.wsdl.legacy.SellGarlicRequest fromCloud(org.system.wsdl.cloud.SellGarlicRequest request);
}
Last but not least, you need to define the first method garlicParameterCollectionToGarlicParameterCollection which surprised me initially.
The reason: MapStruct either tries to:
1. find a mapping method (which is not there if you leave this one out)
or
2. tries to generate a direct mapping (by inspecting if it can find methods for all the attributes on source and target).
However, MapStruct cannot find a direct case for this mapping (it would in principle needs to apply all other possible mappings on its path (e.g. all the methods in the object factory) and then try to generate a mapping method as explained in 2, which could be a lot of combinations. That functionality is not there (and would be load intensive as well I guess).

Related

JsConfig<MyClass>.ExcludePropertyNames example, not working for me

Trying to exclude properties from a model from being included during serialization.
I am using the following syntax:
JsConfig<MyTestClass>.ExcludePropertyNames = new[] { "ShortDescription" };
Just after that I have the following:
return (from o in __someProvider.GetAll() select (new
{
o.Name,
o.ShortDescription
o.InsertDate
}).TranslateTo<MyTestClass>()).ToList()
However once result is returned from the method, it still contains "ShortDescription" field in the Json. Am I doing something wrong?
JsConfig<T>.ExcludePropertyNames appears to be checked only once for each type, in a static constructor for TypeConfig<T>. Thus, if you are configuring ExcludePropertyNames in your service class, just before returning your response, it might be too late -- the TypeConfig properties may already be set up and cached for MyTestClass. I was able to reproduce this.
A more reliable alternative is to move all of your JsConfig<T> configuration to your AppHost setup code.
If you really do need to do this in your service class, e.g. if you are only conditionally excluding property names, then an alternative approach would be to ensure that JsConfig.IncludeNullValues is false (I believe it is by default) and in your service code set ShortDescription to null when appropriate.

How to perform a search on several entities with Symfony 2

I need to perform a search on several entities with the same string then order the results.
I've heard/read a little about FOSElasticaBundle, would this bundle be able to do it? It seems (to me) to have almost to much features for this purpose and I'm not sure it could run on a shared server (hostgator).
The other solution I can think of at the moment is doing the search "manually" (by using join and union) but I'm wondering where should I put such a function: in an existing controller, a new one, a new bundle or somewhere else?
I'm worried as well that this manual solution could come to a cost, especially on some non-indexable fields.
You would do custom entity repositories. Check out the docs. Basically this extends the default FindAll, FindOneBy, etc.
You would have a function like so:
class MyEntityRepository extends Doctrine\ORM\EntityRepository {
public function findByCustomRule(){
//this is mapped to your entity (automatically adds the select)
$queryBuilder = $this->createQueryBuilder('someAlias');
$queryBuilder->orderBy('...');
//this is mapped to any entity
$queryBuilder = $this->getEntityManager()->createQueryBuilder();
$queryBuilder->select('...');
//result
$result = $queryBuilder->getQuery()->getResult();
}
}
This class is defined in the doctrine mapping and lives inside the Entity folder.. Check the docs out and you should get a basic idea.

CRM 2011 Plugin - Does using early bound entities for attribute names cause memory issues?

In my plugin code, I use early bound entities (generated via the crmsvcutil). Within my code, I am using MemberExpression to retrieve the name of the property. For instance, if I want the full name of the user who initiated the plugin I do the following
SystemUser pluginExecutedBy = new SystemUser();
pluginExecutedBy = Common.RetrieveEntity(service
, SystemUser.EntityLogicalName
, new ColumnSet(new string[] {Common.GetPropertyName(() => pluginExecutedBy.FullName)})
, localContext.PluginExecutionContext.InitiatingUserId).ToEntity<SystemUser>();
The code for GetPropertyName is as follows
public static string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression body = (MemberExpression)expression.Body;
return body.Member.Name.ToLower();
}
The code for RetrieveEntity is as follows
public static Entity RetrieveEntity(IOrganizationService xrmService, string entityName, ColumnSet columns, Guid entityId)
{
return (Entity)xrmService.Retrieve(entityName, entityId, columns);
}
My solution architect's comments:
Instead of writing the code like above, why not write it like this (hardcoding the name of the field - or use a struct).
SystemUser pluginExecutedBy = null;
pluginExecutedBy = Common.RetrieveEntity(service
, SystemUser.EntityLogicalName
, new ColumnSet(new string[] {"fullname"})
, localContext.PluginExecutionContext.InitiatingUserId).ToEntity<SystemUser>();
Reason:
Your code unnecessarily creates an object before it requires it (as you instantiate the object with the new keyword before the RetrieveEntity in order to use it with my GetProperty method) which is bad programming practice. In my code, I have never used the new keyword, but merely casting it and casting does not create a new object. Now, I am no expert in C# or .NET, but I like to read and try out different things. So, I looked up the Microsoft.Xrm.Sdk.dll and found that ToEntity within Sdk, actually did create a new Entity using the keyword new.
If the Common.Retrieve returns null, your code has unnecessarily allocated memory which will cause performance issues whereas mine would not?
A managed language like C# "manages the memory" for me, does it not?
Question
Is my code badly written? If so, why? If it is better - why is it? (I believe it is a lot more cleaner and even if a field name changes as long as as the early bound class file is regenerated, I do not have to re-write any code)
I agree that cast does not create a new object, but does my code unnecessarily create objects?
Is there a better way (a completely different third way) to write the code?
Note: I suggested using the GetPropertyName because, he was hard-coding attribute names all over his code and so in a different project which did not use early bound entities I used structs for attribute names - something like below. I did this 3 weeks into my new job with CRM 2011 but later on discovered the magic of MemberExpression. He was writing a massive cs file for each of the entity that he was using in his plugin and I told him he did not have to do any of this as he could just use my GetPropertyName method in his plugin and get all the fields required and that prompted this code review comments. Normally he does not do a code review.
public class ClientName
{
public struct EntityNameA
{
public const string LogicalName = "new_EntityNameA";
public struct Attributes
{
public const string Name = "new_name";
public const string Status = "new_status";
}
}
}
PS: Or is the question / time spent analyzing just not worth it?
Early Bound, Late Bound, MemberExpression, bla bla bla :)
I can understand the "philosophy", but looking at your code a giant alarm popup in my head:
public static Entity RetrieveEntity(IOrganizationService xrmService, string entityName, ColumnSet columns, Guid entityId)
{
return (Entity)xrmService.Retrieve(entityName, entityId, columns);
}
the Retrieve throws an exception if the record is not found.
About the other things, the GetPropertyName is ok, but are always choices, for example I try to use always late bound in plugins, maybe in a project I prefer to use early bound, often there is more than one way to resolve a problem.
Happy crm coding!
Although GetPropertyName is a quite a clever solution I don't like it, and that's entirely to do with readability. To me its far easier to understand what is going on with: new ColumnSet(new string[] {"fullname"}).
But that's pretty much personal preference, but its important to remember that your not just writing code for yourself you are writing it for your team, they should be able to easily understand the work you have produced.
As a side a hardcoded string probably performs better at runtime. I usually hardcode all my values, if the entity model in CRM changes I will have to revisit to make changes in any case. There's no difference between early and late bound in that situation.
I don't understand the point of this function,
public static Entity RetrieveEntity(IOrganizationService xrmService, string entityName, ColumnSet columns, Guid entityId)
{
return (Entity)xrmService.Retrieve(entityName, entityId, columns);
}
It doesn't do anything (apart from cast something that is already of that type).
1.Your code unnecessarily creates an object before it requires it (as you instantiate the object with the new keyword before the
RetrieveEntity in order to use it with my GetProperty method) which is
bad programming practice. In my code, I have never used the new
keyword, but merely casting it and casting does not create a new
object.
I believe this refers to; SystemUser pluginExecutedBy = new SystemUser(); I can see his/her point here, in this case new SystemUser() doesn't do much, but if the object you were instantiating did something resource intensive (load files, open DB connections) you might be doing something 'wasteful'. In this case I would be surprised if changing SystemUser pluginExecutedBy = null; actually yielded any significant performance gain.
2.If the Common.Retrieve returns null, your code has unnecessarily allocated memory which will cause performance issues
I would be surprised if that caused a performance issue, and anyway as Guido points out that function wont return null in any case.
Overall there is little about this code I strongly feel needs changing - but things can be always be better and its worth discussing (e.g. the point of code review), although it can be hard not to you shouldn't be precious about your code.
Personally I would go with hardcoded attribute names and dump the Common.RetrieveEntity function as it doesn't do anything.
pluginExecutedBy = service.Retrieve(SystemUser.EntityLogicalName, localContext.PluginExecutionContext.InitiatingUserId, new ColumnSet(new String[] {"fullname"} ));

XText: permit invalid cross reference

I need to build a grammer containing a cross reference, which may be invalid, i.e. points to a nonexisting target. A file containing such a reference should not yield an error, but only a warning. The generator would handle this as as a special case.
How can I do this with XText?
It's not possible to create valid cross references to non-existing targets in EMF.
I would suggest to go with EAttributes instead of EReferences:
Change the feature=[EClass|ID] by feature=ID in {YourDSL} grammar.
Provide a scope calculation utility like it's done in *scope_EClass_feature(context, reference)* method in the {YourDSL}ScopeProvider class. As this scoping methods simply use the eType of the given reference the reimplementation should be straightforward.
Use this scope calculation utility in {YourDSL}ProposalProvider to propose values for the introduced EAttribute.
Optionally you can use this utility in a validation rule to add a warning/info to this EAttribute if it's not "valid".
Finally use the utility in your generator to create output based on valid target eObjects.
I also ran into this problem when creating a DSL to provide declerations of variables for a none-declerative language for a transition pahse. This method works but ask yourself if you realy want to have those nasty may-references.
You can drop the auto generated error in you UI module only. To do so, provide an ILinkingDiagnosticMessageProvider and override the function getUnresolvedProxyMessage:
class DSLLinkingDiagnosticMessageProvider extends LinkingDiagnosticMessageProvider {
override getUnresolvedProxyMessage(ILinkingDiagnosticContext context) {
if(context.context instanceof YourReference) {
// return null so the your error is left out
null
} else {
// use super implementation for others
super.getUnresolvedProxyMessage(context)
}
}
}
All linker-errors for YourReference will be missed. But be aware that there will be a dummy referenced object with all fealds null. Exspecialy the name ist lost and you can not set it due to a CyclicLinkingException. But you may create a new method that sets the name directly.
Note that the dummy object will have the type you entered in your gramma. If its abstract you can easily check witch reference is not linked.

Why can't I add Contract.Requires in an overridden method?

I'm using code contract (actually, learning using this).
I'm facing something weird to me... I override a method, defined in a 3rd party assembly. I want to add a Contract.Require statement like this:
public class MyClass: MyParentClass
{
protected override void DoIt(MyParameter param)
{
Contract.Requires<ArgumentNullException>(param != null);
this.ExecuteMyTask(param.Something);
}
protected void ExecuteMyTask(MyParameter param)
{
Contract.Requires<ArgumentNullException>(param != null);
/* body of the method */
}
}
However, I'm getting warnings like this:
Warning 1 CodeContracts:
Method 'MyClass.DoIt(MyParameter)' overrides 'MyParentClass.DoIt(MyParameter))', thus cannot add Requires.
[edit] changed the code a bit to show alternatives issues [/edit]
If I remove the Contract.Requires in the DoIt method, I get another warning, telling me I have to provide unproven param != null
I don't understand this warning. What is the cause, and can I solve it?
You can't add extra requirements which your callers may not know about. It violates Liskov's Subtitution Principle. The point of polymorphism is that a caller should be able to treat a reference which actually refers to an instance of your derived class as if it refers to an instance of the base class.
Consider:
MyParentClass foo = GetParentClassFromSomewhere();
DoIt(null);
If that's statically determined to be valid, it's wrong for your derived class to hold up its hands and say "No! You're not meant to call DoIt with a null argument!" The aim of static analysis of contracts is that you can determine validity of calls, logic etc at compile-time... so no extra restrictions can be added at execution time, which is what happens here due to polymorphism.
A derived class can add guarantees about what it will do - what it will ensure - but it can't make any more demands from its callers for overridden methods.
I'd like to note that you can do what Jon suggested (this answers adds upon his) but also have your contract without violating LSP.
You can do so by replacing the override keyword with new.
The base remains the base; all you did is introduce another functionality (as the keywords literally suggest).
It's not ideal for static-checking because the safety could be easily casted away (cast to base-class first, then call the method) but that's a must because otherwise it would violate LSP and you do not want to do that obviously. Better than nothing though, I'd say.
In an ideal world you could also override the method and call the new one, but C# wouldn't let you do so because the methods would have the same signatures (even tho it would make perfect sense; that's the trade-off).

Resources