Using Modelmapper, how do I map to a class with no default/no-args constructor? - modelmapper

I want to map to a source destination which only have a constructor that takes 3 parameters. I get the following error:
Failed to instantiate instance of destination com.novasol.bookingflow.api.entities.order.Rate. Ensure that com.novasol.bookingflow.api.entities.order.Rate has a non-private no-argument constructor.
It works when I insert a no-args constructor in the source destination, but that can lead to misuse of the class, so I would rather not o that.
I have tried using a Converter, but that does not seem to work:
Converter<RateDTO, Rate> rateConverter = new AbstractConverter<RateDTO, Rate>() {
protected Rate convert(RateDTO source) {
CurrencyAndAmount price = new CurrencyAndAmount(source.getPrice().getCurrencyCode(), source.getPrice().getAmount());
Rate rate = new Rate(price, source.getPaymentDate(), source.getPaymentId());
return rate;
}
};
Is it possible to tell modelmapper how to map to a destination with a no no-args constructor?

This seemed to do the trick:
TypeMap<RateDTO, Rate> rateDTORateTypeMap = modelMapper.getTypeMap(RateDTO.class, Rate.class);
if(rateDTORateTypeMap == null) {
rateDTORateTypeMap = modelMapper.createTypeMap(RateDTO.class, Rate.class);
}
rateDTORateTypeMap.setProvider(request -> {
RateDTO source = RateDTO.class.cast(request.getSource());
CurrencyAndAmount price = new CurrencyAndAmount(source.getPrice().getCurrencyCode(), source.getPrice().getAmount());
return new Rate(price, source.getPaymentDate(), source.getPaymentId());
});

Related

Eclipse JDT resolve unknown kind from annotation IMemberValuePair

I need to retrieve the value from an annotation such as this one that uses a string constant:
#Component(property = Constants.SERVICE_RANKING + ":Integer=10")
public class NyServiceImpl implements MyService {
But I am getting a kind of K_UNKNOWN and the doc says "the value is an expression that would need to be further analyzed to determine its kind". My question then is how do I perform this analysis? I could even manage to accept getting the plain source text value in this case.
The other answer looks basically OK, but let me suggest a way to avoid using the internal class org.eclipse.jdt.internal.core.Annotation and its method findNode():
ISourceRange range = annotation.getSourceRange();
ASTNode annNode = org.eclipse.jdt.core.dom.NodeFinder.perform(cu, range);
From here on you should be safe, using DOM API throughout.
Googling differently I found a way to resolve the expression. Still open to other suggestions if any. For those who might be interested, here is a snippet of code:
if (valueKind == IMemberValuePair.K_UNKNOWN) {
Annotation ann = (Annotation)annotation;
CompilationUnit cu = getAST(ann.getCompilationUnit());
ASTNode annNode = ann.findNode(cu);
NormalAnnotation na = (NormalAnnotation)annNode;
List<?> naValues = na.values();
Optional<?> optMvp = naValues.stream()
.filter(val-> ((MemberValuePair)val).getName().getIdentifier().equals(PROPERTY))
.findAny();
if (optMvp.isPresent()) {
MemberValuePair pair = (MemberValuePair)optMvp.get();
if (pair.getValue() instanceof ArrayInitializer) {
ArrayInitializer ai = (ArrayInitializer)pair.getValue();
for (Object exprObj : ai.expressions()) {
Expression expr = (Expression)exprObj;
String propValue = (String)expr.resolveConstantExpressionValue();
if (propValue.startsWith(Constants.SERVICE_RANKING)) {
return true;
}
}
}
else {
Expression expr = pair.getValue();
String propValue = (String)expr.resolveConstantExpressionValue();
if (propValue.startsWith(Constants.SERVICE_RANKING)) {
return true;
}
}
}
//report error
}
private CompilationUnit getAST(ICompilationUnit compUnit) {
final ASTParser parser = ASTParser.newParser(AST.JLS8);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setSource(compUnit);
parser.setResolveBindings(true); // we need bindings later on
CompilationUnit unit = (CompilationUnit)parser.createAST(null);
return unit;
}

Variable outside local scope is not defined for test case

I wish to access outside variables for a test function that I am writing, in Groovy.
However, it doesn't seem that I can.
My code is like this:
Map<String, String> originalTableRowState = new HashMap<String, String>(),
newTableRowState
// if there is table data to get, and do actions on
def WebDriver driver = DriverFactory.getWebDriver()
def List<WebElement> dataRows = driver.findElements(
By.cssSelector('div.tab-pane.active .dataTables_scrollBody tbody tr:not(.dataTables_empty)'))
'if there\'s table data, this test should run'
if (dataRows.size() > 0) {
WebUI.comment('populate the tableRowState with the data from the first table row')
fetchFirstRowDataInto(originalTableRowState)
}
void fetchFirstRowDataInto(Map<String, String> tableRowState) {
List<WebElement> tableHeadings = driver.findElements(
By.cssSelector('div.tab-pane.active .dataTables_scrollHead th'))
WebElement firstRow = dataRows.get(0)
List<WebElement> dataCells = firstRow.findElements(
By.xpath('//td[not(#class="dataTables_empty") and not(*)]'))
for (int i = 0; i < dataCells.size(); i++) {
// save data to originalTableRowState with the table header text as the key
tableRowState.put(tableHeadings.get(i), dataCells.get(i))
}
}
and when I run it, it greets me with the error saying that Variable 'driver' is not defined outside test case. I just added the def keywords to the driver,dataRows definintions.
How to make driver,dataRows accessible inside functions, without passing them in as parameters?
I fixed the method variable-access issue by declaring it a JS-like closure:
/* change void fetchFirstRowDataInto(Map<String, String> tableRowState) { to def fetchFirstRowDataInto = { Map<String, String> tableRowState -> */
and putting the definition above the invocation.
I welcome any better solutions...

AST Transformation to wrap entire method body in a closure

I'm trying to do something rather simple. I would like to wrap the whole method code into an additional closure block that would measure the execution time. Right now I'm getting a really not helpful error message:
Error:Groovyc: NPE while processing Test.groovy
Annotation:
#Retention(RetentionPolicy.SOURCE)
#Target([ElementType.METHOD])
#GroovyASTTransformationClass(["WithTimingASTTransformation"])
public #interface WithTiming {
}
My wrapping closure:
class Benchmark {
static def measureTime(Closure cl) {
def start = System.currentTimeMillis()
def result = cl()
def time = System.currentTimeMillis() - start
println "it took $time"
result
}
}
My Transformation:
#GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
class WithTimingASTTransformation implements ASTTransformation {
#Override
void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
MethodNode method = astNodes[1]
method.code = wrap(method)
}
private Statement wrap(MethodNode method) {
def newBlock = new BlockStatement()
newBlock.addStatement(
new ExpressionStatement(
new StaticMethodCallExpression(
new ClassNode(Benchmark),
'measureTime',
new ArgumentListExpression(
new ClosureExpression(new Parameter[0], method.code)
))))
newBlock
}
}
I'm really stuck here and don't know how can I debug the problem.
There is an answer on a similar topic (wrapping whole method body into a try/catch block here). This works fine but my case is slightly different.
In my case similar NPE was coming from:
java.lang.NullPointerException
at org.codehaus.groovy.classgen.asm.ClosureWriter.createClosureClass(ClosureWriter.java:194)
at org.codehaus.groovy.classgen.asm.ClosureWriter.getOrAddClosureClass(ClosureWriter.java:159)
at org.codehaus.groovy.classgen.asm.ClosureWriter.writeClosure(ClosureWriter.java:90)
at org.codehaus.groovy.classgen.AsmClassGenerator.visitClosureExpression(AsmClassGenerator.java:673)
Whereas:
if (parameters == null || expression.getVariableScope() == null) {
parameters = Parameter.EMPTY_ARRAY;
} else if (parameters.length == 0) {
// let's create a default 'it' parameter
Parameter it = new Parameter(ClassHelper.OBJECT_TYPE, "it", ConstantExpression.NULL);
parameters = new Parameter[]{it};
Variable ref = expression.getVariableScope().getDeclaredVariable("it");
if (ref != null) it.setClosureSharedVariable(ref.isClosureSharedVariable());
}
and line 194 (as of https://github.com/groovy/groovy-core/commit/a52d0d3c5dd1cbb342992d36235171718a563c8b) is:
Variable ref = expression.getVariableScope().getDeclaredVariable("it");
Thus you need to define a VariableScope for your ClosureExpression. I had to add tracing into org.codehaus.groovy.ast.ClosureWriter to find this, because there is an issue with exception display on stage of Class Generation - both in IntelliJ Idea and in Groovy Console - it does not show proper lines of code.
Furthermore, I think that either ClosureWriter or ClosureExpression constructor can be fixed to work aligned by default - without this NPE. I will possibly submit an issue to Groovy Jira for this.
Now I am able to inject closure expression in my code. But struggling to call this closure.
Getting:
groovy.lang.MissingMethodException: No signature of method: com.a9ae0b01f0ffc.VSMSGEN.implementation.T_visa_recon_generator$_convert_vts_log_to_ctf_closure2.call() is applicable for argument types: () values: []
Long story short, after some iterations my method-wrapping AST looks like this:
BlockStatement bs = new BlockStatement()
ClosureExpression closureExp = new ClosureExpression( methodNode.parameters, methodNode.code )
closureExp.variableScope = new VariableScope() // <- this does the trick!
bs.addStatement new ExpressionStatement( new StaticMethodCallExpression( new ClassNode( TransactionUtil ), 'wrap', new ArgumentListExpression( closureExp ) ) )
methodNode.code = bs
The line closureExp.variableScope = new VariableScope() avoids the NPE in ClosureWriter.java:194 and the whole thing runs like a charm!
Hope it helps someone...

Using objects as Map keys in Haxe

I'm trying to make a Map with an object as a key. The problem is, that when I try to get elements from this map, I always get null. It's because I'm not providing the exact same reference as the key was. I'm providing an object with the same values, so the reference is different.
Is there any way to solve that? Can I make it use some kind of equals() function?
class PointInt
{
public var x:Int;
public var y:Int;
...
}
var map = new Map<PointInt, Hex>();
var a = new PointInt(1, 1);
var b = new PointInt(1, 1);
var hex_a = new Hex();
map[a] = hex_a;
var hex_b = map[b];
/// hex_b == null now because reference(a) == reference(b)
As explained here and here, Map in Haxe works using the reference of the object as the key.
What you want to use instead is a HashMap like this (try.haxe link):
import haxe.ds.HashMap;
class Test {
static function main() {
var map = new HashMap();
map.set(new PointInt(1, 1), 1);
trace(map.get(new PointInt(1,1)));
}
}
class PointInt
{
public var x:Int;
public var y:Int;
public function new(x:Int, y:Int)
{
this.x = x;
this.y = y;
}
public function hashCode():Int
{
return x + 1000*y; //of course don't use this, but a real hashing function
}
public function toString()
{
return '($x,$y)';
}
}
What you need to change in your code, besides using haxe.ds.HashMap instead of Map is to implement a hashCode : Void->Int function in your key object
Since you're using an object that has 2 ints, and the hash map is just 1 int, it will happen that 2 PointInt will have the same hash code. To solve this you could create a hash map that uses strings as hashcode but if you can write (or google) a good hash function you will get better performance.

Anonymous type and getting values out side of method scope

I am building an asp.net site in .net framework 4.0, and I am stuck at the method that supposed to call a .cs class and get the query result back here is my method call and method
1: method call form aspx.cs page:
helper cls = new helper();
var query = cls.GetQuery(GroupID,emailCap);
2: Method in helper class:
public IQueryable<VariablesForIQueryble> GetQuery(int incomingGroupID, int incomingEmailCap)
{
var ctx = new some connection_Connection();
ObjectSet<Members1> members = ctx.Members11;
ObjectSet<groupMember> groupMembers = ctx.groupMembers;
var query = from m in members
join gm in groupMembers on m.MemberID equals gm.MemID
where (gm.groupID == incomingGroupID) && (m.EmailCap == incomingEmailCap)
select new VariablesForIQueryble(m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap);
//select new {m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap};
return query ;
}
I tried the above code with IEnumerable too without any luck. This is the code for class VariablesForIQueryble:
3:Class it self for taking anonymouse type and cast it to proper types:
public class VariablesForIQueryble
{
private int _emailCap;
public int EmailCap
{
get { return _emailCap; }
set { _emailCap = value; }
}`....................................
4: and a constructor:
public VariablesForIQueryble(int memberID, string memberFirst, string memberLast, string memberEmail, int? validEmail, int? emailCap)
{
this.EmailCap = (int) emailCap;
.........................
}
I can't seem to get the query result back, first it told me anonymous type problem, I made a class after reading this: link text; and now it tells me constructors with parameters not supported. Now I am an intermediate developer, is there an easy solution to this or do I have to take my query back to the .aspx.cs page.
If you want to project to a specific type .NET type like this you will need to force the query to actually happen using either .AsEnumerable() or .ToList() and then use .Select() against linq to objects.
You could leave your original anonymous type in to specify what you want back from the database, then call .ToList() on it and then .Select(...) to reproject.
You can also clean up your code somewhat by using an Entity Association between Groups and Members using a FK association in the database. Then the query becomes a much simpler:
var result = ctx.Members11.Include("Group").Where(m => m.Group.groupID == incomingGroupID && m.EmailCap == incomingEmailCap);
You still have the issue of having to do a select to specify which columns to return and then calling .ToList() to force execution before reprojecting to your new type.
Another alternative is to create a view in your database and import that as an Entity into the Entity Designer.
Used reflection to solve the problem:
A: Query, not using custom made "VariablesForIQueryble" class any more:
//Method in helper class
public IEnumerable GetQuery(int incomingGroupID, int incomingEmailCap)
{
var ctx = new some_Connection();
ObjectSet<Members1> members = ctx.Members11;
ObjectSet<groupMember> groupMembers = ctx.groupMembers;
var query = from m in members
join gm in groupMembers on m.MemberID equals gm.MemID
where ((gm.groupID == incomingGroupID) && (m.EmailCap == incomingEmailCap)) //select m;
select new { m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap };
//select new VariablesForIQueryble (m.MemberID, m.MemberFirst, m.MemberLast, m.MemberEmail, m.ValidEmail, m.EmailCap);
//List<object> lst = new List<object>();
//foreach (var i in query)
//{
// lst.Add(i.MemberEmail);
//}
//return lst;
//return query.Select(x => new{x.MemberEmail,x.MemberID,x.ValidEmail,x.MemberFirst,x.MemberLast}).ToList();
return query;
}
B:Code to catch objects and conversion of those objects using reflection
helper cls = new helper();
var query = cls.GetQuery(GroupID,emailCap);
if (query != null)
{
foreach (var objRow in query)
{
System.Type type = objRow.GetType();
int memberId = (int)type.GetProperty("MemberID").GetValue(objRow, null);
string memberEmail = (string)type.GetProperty("MemberEmail").GetValue(objRow, null);
}
else
{
something else....
}

Resources