Mapstruct Optional into Optional - mapstruct

I'm trying to map a optional into another one.
I did the following but I get an error:
Optional<User> does not have an accessible constructor
#Mapper( componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE )
public interface UserMapper {
Optional<User> map (Optional<UserModel> userModel);
}
How can I map a optional into another?
Thanks

Optional is not yet supported
see this issue : https://github.com/mapstruct/mapstruct/pull/2874

Related

C# Dynamic IEnumerable <class>

Anyone know how to pass the IEnumerable<xxxxx> into method. XXXXX is refer to any class.
I want to make it dynamic to accept any class. Example, <student>, <course>, <semester>, etc.
Currently it is fixed as Employee class.
public IEnumerable<Employee> GetJsonFile(string strFolder, string strFileName)
{
string strFile = Path.Combine(WebHostEnvironment.WebRootPath, strFolder, strFileName);
using (var jsonFileReader = File.OpenText(strFile))
{
return JsonSerializer.Deserialize<Employee[]>(jsonFileReader.ReadToEnd(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true});
}
}
Use Generics. IEnumerable<T> Where T is a class.
Generics Guide
Instead of using <Employee> use <T>
public IEnumerable<T> GetJsonFile<T>(string strFolder, string strFileName)
{
...return JsonSerializer.Deserialize<T[]>...
}
Then when you call the method you supply it with the type.
var x = GetJsonFile<student>(folder,file);
For more information lookup information on C# Generics.

Convert List to another List with multiple parameters

I have an existing mapping of 2 objects ExpertJpa to ExpertDto that need another param to filter ExpertJpa.
This map working properly and now I try to convert List of ExpertJpa to List of ExpertDto, I add this second param.
#Mappings({
#Mapping(target = "status", ignore = true),
#Mapping(target = "profile", source = "input.expertProfile"),
#Mapping(target = "engagementId", expression = "java(new MapperHelper().ReturnExpertEngagementIdByApiKey(input,identity))"),
#Mapping(target = "campaignId", expression = "java(new MapperHelper().ReturnExpertCampaignIdByApiKey(input,identity))"),
})
Expert ExpertJpaToExpert(com.consumer.expert.dbaccessor.entities.Expert input, Identity identity);
List<Expert> ListExpertsJpaToListExperts(List<com.consumer.expert.dbaccessor.entities.Expert> input, Identity identity);
On build, I get Error message that List is an interface and cannot be instance....
Error:(53, 18) java: The return type java.util.List is an abstract class or interface. Provide a non abstract / non interface result type or a factory method.
MapStruct can do this automatically for you. However it cannot handle multiple argument methods (in principle it maps source to target).
Having said that, if you rewrite your code a little bit it you could get rid of the expression and have a full type safe solution.
So:
class IdentityContext {
private final Identity id;
private final MapperHelper mapperHelper;
public IdentityContext(Identity id){
this.id = id;
this.mapperHelper = new MapperHelper();
}
#AfterMapping
public void setIds(com.consumer.expert.dbaccessor.entities.Expert input, #MappingTarget Expert expertOut) {
expertOut.setEngagementId( mapperHelper.ReturnExpertEngagementIdByApiKey(input,identity) );
expertOut.setCampaignId( mapperHelper. ReturnExpertCampaignIdByApiKey(input,identity) );
}
}
now define your mapper as such:
#Mappings({
#Mapping(target = "status", ignore = true),
#Mapping(target = "profile", source = "input.expertProfile")
})
Expert ExpertJpaToExpert(com.consumer.expert.dbaccessor.entities.Expert input, #Context IdentityContext ctx);
List<Expert> ListExpertsJpaToListExperts(List<com.consumer.expert.dbaccessor.entities.Expert> input, #Context IdentityContext ctx)
Note: MapStruct will now recognise the list mapping because the IdentityContext is marked as #Context (so: it will be only set in the calling method but in essence not be part of the mapping source-target itself).

Unable to cast the type 'System.Int32' to type 'System.Object during EF Code First Orderby Function

I'm using Specification pattern in EF Code First. When I do order by operation, VS throw a new exception
The specification pattern is copy from eShopOnWeb
I just change a little bit, here is my change code:
public class Specification<T> : ISpecification<T>
{
public Expression<Func<T, object>> OrderBy { get; private set; }
public Specification(Expression<Func<T, bool>> criteria)
{
Criteria = criteria;
}
public Specification<T> OrderByFunc(Expression<Func<T, object>> orderByExpression)
{
OrderBy = orderByExpression;
return this;
}
}
Here is my invoke code, it's very pretty simple:
static void TestSpec()
{
var spec = new Specification<ExcelData>(x => x.RowIndex == 5)
.OrderByFunc(x => x.ColumnIndex);
using (var dbContext = new TechDbContext())
{
var top10Data = dbContext.ExcelData.Take(10).ToList();
var listExcel = dbContext.ApplySpecification(spec).ToList();
Console.WriteLine();
}
}
If I comment OrderByFunc, then everything is fine to me. no error throw from vs.
I had try many times search the error message in google, but none of answer is my case.
So I have to ask a question in here.
When I debug OrderBy property in SpecificationEvaluator.cs, I found there is a Convert method.
So I know the error is about cast error, but how do I fix this cast type error?
Please help me!
The solution is to create new lambda expression with cast (Convert) removed, and then use it to call the Queryable class OrderBy / OrderByDescending method either dynamically (using DLR dispatch or reflection) or by emitting Expression.Call to it.
For the first part, add the following helper method to the SpecificationEvaluator class:
static LambdaExpression RemoveConvert(LambdaExpression source)
{
var body = source.Body;
while (body.NodeType == ExpressionType.Convert)
body = ((UnaryExpression)body).Operand;
return Expression.Lambda(body, source.Parameters);
}
Then replace the code
query = query.OrderBy(specification.OrderBy);
with either
query = Queryable.OrderBy((dynamic)query, (dynamic)RemoveConvert(specification.OrderBy));
or
var keySelector = RemoveConvert(specification.OrderBy);
query = query.Provider.CreateQuery<T>(Expression.Call(
typeof(Queryable), nameof(Queryable.OrderBy),
new[] { typeof(T), keySelector.ReturnType },
query.Expression, keySelector));
Do similar for the specification.OrderByDescending.

How to resolve public class with internal constructor on AutoFac

I have this class to be instantiated in a unittest:
public class Customer
{
internal Customer(Guid id) {
// initialize property
}
}
If I instantiate the test class from another (unittests) assembly with a new Customer() works because I added [assembly: InternalsVisibleTo("MyProject.Tests")]
var sut = new Customer(Guid.NewGuid()); // works
But when i setup an autofac container in the other (unittest) assembly
var builder = new ContainerBuilder();
builder.RegisterType<Customer>().AsSelf();
var container = builder.Build();
I can't resolve with autofac.
var theParam = new NamedParameter("id", Guid.NewGuid());
_sut = container.Resolve<Customer>(theParam); // throws exception
My best guess was that the internal constructor was not available. But adding [assembly: InternalsVisibleTo("Autofac")] next to the other doesn't help.
The exception thown by Autofac is
Autofac.Core.DependencyResolutionException:
An error occurred during the activation of a particular registration. See the inner exception for details.
Registration: Activator = Customer (ReflectionActivator),
Services = [MyProject.Customer],
Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime,
Sharing = None,
Ownership = OwnedByLifetimeScope
---> No accessible constructors were found for the type 'MyProject.Customer'.
Can Autofac not handle internal constructors?
Autofac can't locate non-public constructors because it uses the DefaultConstructorFinder class which searches only for public constructors by default.
You have to create your custom implementation of the IConstructorFinder interface like this:
public class AllConstructorFinder : IConstructorFinder
{
private static readonly ConcurrentDictionary<Type, ConstructorInfo[]> Cache =
new ConcurrentDictionary<Type, ConstructorInfo[]>();
public ConstructorInfo[] FindConstructors(Type targetType)
{
var result = Cache.GetOrAdd(targetType,
t => t.GetTypeInfo().DeclaredConstructors.Where(c => !c.IsStatic).ToArray());
return result.Length > 0 ? result : throw new NoConstructorsFoundException(targetType);
}
}
Then you have to use the FindConstructorsWith extension method on type registration:
builder.RegisterType<Customer>()
.FindConstructorsWith(new AllConstructorFinder())
.AsSelf();
The InternalsVisibleToAttribute can't help in this case because it affects only the compile time.
if you want to register assembly types with at least only has one public constructor then you can use Autofac Where extension method like this.
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.GetConstructors().Length > 0) //only public constructors
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
Note: PublicOnly extension method registers only public types.

Class constructor and interfaces

How do I properly type Classes that implement interfaces?
Example code:
interface IPlugin{
name:string;
}
class SomePlugin implements IPlugin{
name;
constructor(){
this.name = 'Sam';
}
}
const arrayOfClass:IPlugin = [SomePlugin];
// Ther error :
/*
Type 'typeof SomePlugin[]' is not assignable to type 'IPlugin'.
Property 'name' is missing in type 'typeof SomePlugin[]'.
*/
How should I go about this?
Create an interface that describes objects that will instantiate objects that implement IPlugin. You can do this by using a new signature:
interface IPluginConstructor {
new(...args: any[]): IPlugin;
}
Now type arrayOfClass as an array of IPluginConstructors:
const arrayOfClass: IPluginConstructor[] = [SomePlugin];
Note the [] in the type. That was absent in the question.
Sidenote
If you look closely, the type of name is any in SomePlugin... it's been set as any because the type was implicitly typed as any and string is assignable to any. That means the following code compiles:
const s = new SomePlugin();
const num: number = s.name; // this compiles... sad! :(
You should type that either explicitly...
class SomePlugin implements IPlugin {
name: string;
constructor() {
this.name = 'Sam';
}
}
...or implicitly...
class SomePlugin implements IPlugin {
name = 'Sam';
}
I recommend you enable the noImplicitAny compiler flag to help catch these kind of mistakes in the future.