I have already successfully used a Provider in a ModelMapper transformation but I've stumbled upon a weird situation. I've noticed that the Provider is being considered only for the objects beyond the "first level" of the transformation, eg.:
I have two hierarchies:
1st) TipoConsultarProcessoResposta, TipoProcessoJudicial and TipoDocumento
2nd) ConsultarProcessoResposta, ProcessoJudicial and Documento
TipoConsultarProcessoResposta has a TipoProcessoJudicial that in turn has a List of TipoDocumento, the 2nd hierarchy ressembles the first.
I am converting from the first hierarchy to the second and the provider is working fine for the TipoDocumento to Documento conversion but it is being ignored for the conversion of TipoProcessoJudicial to ProcessoJudicial.
Here is the relevant part of the code:
modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(STRICT);
modelMapper.addMappings(new DocumentoPropertyMap()).setProvider(documentoProvider);
modelMapper.addMappings(new ProcessoJudicialPropertyMap()).setProvider(processoJudicialProvider);
ConsultarProcessoResposta resposta = modelMapper.map(tipoConsultarProcessoResposta, ConsultarProcessoResposta.class);
DocumentoPropertyMap extends PropertyMap<TipoDocumento, Documento> and ProcessoJudicialPropertyMap extends PropertyMap<TipoProcessoJudicial, ProcessoJudicial>.
The thing is that the DocumentoProvider is being called but ProcessoJudicialProvider isn't being called. ModelMapper tries to invoke a Global Provider that fails as well and resorts to instantiating through the constructor.
Related
I am using Nomin for mapping tasks. As taken from the documentation of Nomin it should be able to map fields with the same name by itself in case automapping has been activated. When activating it, it causes an infinite loop exception.
I have the following:
mappingFor a: CoinsOnMarketPlace, b: Coin
// automap() // when deactivated it works fine, when activated infinite loop
a.coin.name = b.name
a.coin.rank = b.rank
a.priceUSD = b.priceUSD // Could be automapped
a.priceBTC = b.priceBTC // Could be automapped
...
Exception:
org.nomin.core.NominException: ./net/hemisoft/ccm/repository/coinmarketcap2coin.groovy: Recursive mapping rule a = b causes infinite loop!
One thing worth adding regarding your use case - this Recursive mapping rule a = b causes infinite loop! exception is thrown because you use groovy classes in your mapping rule. Nomin uses ReflectionIntrospector and what's important:
It performs getting/setting properties using accessor methods which are called through the Java reflection mechanism. ReflectionIntrospector uses supplied NamingPolicy instance to determine accessor methods. JbNamingPolicy is used by default, this implementation cerresponds the JavaBeans convention. Its InstanceCreator named ReflectionInstanceCreator instantiates objects using Class.newInstance().
Source: http://nomin.sourceforge.net/introspectors.html
A simple Groovy class like:
class Entity {
String name
String somethingElse
}
gets compiled to a Java class that implements GroovyObject providing following methods:
public interface GroovyObject {
Object invokeMethod(String var1, Object var2);
Object getProperty(String var1);
void setProperty(String var1, Object var2);
MetaClass getMetaClass();
void setMetaClass(MetaClass var1);
}
In this case ReflectionInstanceCreator combined with automap() resolves following mappings:
a.property = b.property
and
a = b
where a = b mapping comes from MetaClass getMetaClass() getter method I suppose, because there is no mapping like a.metaClass = b.metaClass resolved. a.property = b.property gets resolved because of Object getProperty(String var1) method.
Solution
This problem can be solved by specifying explicitly ExplodingIntrospector for your mapping script that:
It performs getting/setting properties using a class field immediately through through the Java reflection mechanism and may be useful in case when domain object don't provide accessors for their properties. Supplied instance creator is ReflectionInstanceCreator.
Source: http://nomin.sourceforge.net/introspectors.html
All you have to do is to add
introspector exploding
right below mappingFor a: ..., b: ... header. For example:
import mypackage.Entity
import mypackage.EntityDto
mappingFor a: Entity, b: EntityDto
introspector exploding
automap()
a.test2 = b.test1
Tested with two Groovy classes, worked like a charm. Hope it helps.
I'm using Spring Data Cassandra 1.3.4.RELEASE to persist instances of a class that I have. The class is written in Groovy, but I don't think that really matters. I have implemented a CrudRepository, and I'm injecting an instance of CassandraOperations into the repo implementation class. I can insert, delete, and do most of the other operations successfully. However, there's a scenario I'm running into which breaks my test case. My entity class looks something like this:
#Table("foo")
class FooData {
#PrimaryKey("id")
long id
#Column("created")
long updated
#Column("name")
String name
#Column("user_data")
String userData
#Column("numbers")
List numberList = []
}
In my test case, I happened to only set a few fields like 'id' and 'updated' before calling CassandraOperations.insert(entity), so most of them were null in the entity instance at the time of insertion. But the numberList field was not null, it was an empty List. Directly after the insert(), I'm calling CassandraOperations.selectOneById(FooData.class, id). I get a FooData instance back, and the fields that were initialized when I saved it are populated with data. However, I was checking content equality in my test, and it failed because the empty list was not returned as an empty list in the POJO coming back from CassandraOperations.selectOneById(). It's actually null. I assume this may be some sort of Cassandra optimization. It seems to happen in the CGLIB code that instantiates the POJO/entity. Is this a known "feature"? Is there some annotation I can mark the 'numberList' field with to indicate that it cannot be null? Any leads are appreciated. Thanks.
In short
Cassandra stores empty collections as null and Spring Data Cassandra overwrites initialized fields.
Explanation
Cassandra list/set typed columns represent an empty collection as null. It does not matter whether the list/set (as viewed from Java/Groovy) was empty or null. Storing an empty list yields therefore in null. From here one can't tell whether the state was null or empty at the time saving the value.
Spring Data Cassandra overwrites all fields with values retrieved from the result set and so your pre-initialized fields is set to null.
I created a ticket DATACASS-266 to track the state of this issue.
Workaround
Spring Data uses setters if possible so you have a chance to intervene. A very simple null guard could be:
public void setMyList(List<Long> myList) {
if(myList == null){
this.myList = new ArrayList<>();
return;
}
this.myList = myList;
}
As important addition to mp911de answer you have to set #org.springframework.data.annotation.AccessType(AccessType.Type.PROPERTY) to make this solution work.
I currently have a xtext grammar that looks like the following :
Features:
'feature' name = ID
'{'(
('action' '{' action+=Actions (',' action+=Actions)* '}')? &
('dependencies' '{' dependencies = Dependencies '}')? &
('children' '{' children = Children '}')?
)'}'
;
What I want to do with this is add an action to an already existing source file programatically, for that I am using the IUnitOfWork.Void class that I subclass for easier implementation , it currently looks like this (the meaningful part of it) :
final XtextEditor editor = (XtextEditor)sourcepart;
final IXtextDocument document = editor.getDocument();
document.modify(new IUnitOfWork.Void<XtextResource>(){
public void process (XtextResource resource) throws Exception {
IParseResult parseResult = resource.getParseResult();
if(parseResult ==null)
return;
CompositeNode rootNode=(CompositeNode) parseResult.getRootNode();
LeafNode node = (LeafNode)NodeModelUtils.findLeafNodeAtOffset(rootNode, 0);
EObject object =NodeModelUtils.findActualSemanticObjectFor(node);
Through this I traverse the tree of the model and get to my Features object to which I want to add an action to (this is done through a pop up menu in a custom Tree View I'm implementing)
Here's my problem : whenever I want to add an action it screws up the way the tags are placed in the source file , and by that I mean that instead of :
action {
act1.set (foo),
act2.set (bar),
act3.set (baz),
act4.set (booze) //where this is the new action that I add
}
it will add it as
action {
act1.set (foo),
act2.set (bar),
act3.set (baz)
}
action {
act4.set(booze)
}
And this is illegal by the rules of my grammar, and I'm not allowed to change the way it should be written. (I am allowed to make small changes to the way the rules are implemented, but would really want to avoid it as it would mean a whole new amount of work to reimplement other things that depend on them)
I've tried :
adding it directly through Features.getAction().add(*the new action);
copying the items in the list into an array with the toArray() method so as to avoid referencing, adding my action to the array, clearing the list then adding all the elements again one by one
creating an entirely new Features object and setting everything in it to be the same as the currently edited one then replacing the feature with the new one
And I'm out of ideas after that. The frustrating part is that the 3rd method worked for a different kind of object in my grammar and had no errors there.
How could I make this work ?
this is a bug in xtext. (can you please file a ticket?)
as a workaround you may use the following
Features:
'feature' name = ID
'{'(
('action' '{' actionList=ActionList '}')? &
('dependencies' '{' dependencies = Dependencies '}')? &
('children' '{' children = Children '}')?
)'}';
ActionList:
(action+=Action (',' action+=Action)*)
;
i have a problem with the Dialog control from the Extention library:
I have created a java custom control wich searches some views, collects some data and displays it. This works nice if i place it on a XPage.
But i want to display the data in a Dialog so i used the Dialog control from the extention library. Using the Dialog control without any configuration also works fine but it takes some time for my control to search the views and display the data every time i open the dialog.So to reduce the waiting time for the user i wanted to use the option "keepComponents="true" from the Dialog control.
Now if i open the Dialog for the first time everything is perfekt but if i open it a secound time it displays the content from the first opening in addition to an error from my controlRenderer wich tells me that it could not get the viewName from the control. This error stacks up for every time i open and close the dialog.
I found a Post on OpenNtf from somebody who had the same issue with multiple content in his dialog when using this option but he didnt get any answers to his question.
Is this a bug of the component? Should i forget this option and cache my data in a bean? Why can't the renderer get the Viewname from the component?
The answer that follows assumes that the phrase "java custom control" in your question refers to a JSF component you developed; in XPages, the term "custom control" usually refers to an instance of a Custom Control design element, which is IBM's implementation of the JSF notion of "composite components".
You've stated that the component initially behaves as intended but fails on subsequent requests. This typically indicates that the restoreState and saveState methods of the component have not been properly implemented.
When the default serialization options are enabled for an application, all component state is written to disk at the end of each request, and read back into memory at the beginning of the next. These two operations are handled, respectively, by the saveState and restoreState methods of each component.
For example, suppose you defined a component for adding HTML canvas tags to an XPage, and decided to support the gesture and touch events associated with that element. So your component class would contain fields to store any code bound to those events:
private String ongesturechange;
private String ongestureend;
private String ongesturestart;
private String ontouchcancel;
private String ontouchend;
private String ontouchmove;
private String ontouchstart;
Each of those fields would typically then have an associated "getter" and "setter" method:
public String getOngesturechange() {
return getStringProperty("ongesturechange", this.ongesturechange);
}
public void setOngesturechange(String ongesturechange) {
this.ongesturechange = ongesturechange;
}
When an instance of that component is initialized, the "setter" method associated with each attribute that is defined for that component instance will be passed the value defined for that attribute. For the remainder of the initial page request, then, the private field for each defined attribute will store the value that was set. At the end of the request, the saveState method writes the values of these fields to disk. A typical saveState method looks similar to the following:
#Override
public Object saveState(FacesContext context) {
Object[] properties = new Object[8];
int idx = 0;
properties[idx++] = super.saveState(context);
properties[idx++] = this.ongesturechange;
properties[idx++] = this.ongestureend;
properties[idx++] = this.ongesturestart;
properties[idx++] = this.ontouchcancel;
properties[idx++] = this.ontouchend;
properties[idx++] = this.ontouchmove;
properties[idx++] = this.ontouchstart;
return properties;
}
The call to super.saveState() executes the same method, but using the version of the method defined in the parent class. So the on-disk representation of each component is essentially a nested array: each layer in the hierarchy stores all the properties it inherits from its parent class in the first element of the array, then stores all the properties that it defines in additional array elements.
When the component tree is restored on subsequent requests, each component uses its restoreState method to reconstitute the values of all its fields. A typical restoreState method looks similar to the following:
#Override
public void restoreState(FacesContext context, Object state) {
Object[] properties = (Object[]) state;
int idx = 0;
super.restoreState(context, properties[idx++]);
this.ongesturechange = ((String) properties[idx++]);
this.ongestureend = ((String) properties[idx++]);
this.ongesturestart = ((String) properties[idx++]);
this.ontouchcancel = ((String) properties[idx++]);
this.ontouchend = ((String) properties[idx++]);
this.ontouchmove = ((String) properties[idx++]);
this.ontouchstart = ((String) properties[idx++]);
}
This hierarchically reads the on-disk data back in: each class passes a set of properties to the parent class, then assigns the remaining array elements to the fields they were associated with when the component state was saved.
This process provides an easy way to maintain component state across requests -- each layer of inheritance need only concern itself with the new properties that layer defines -- but these state maintenance methods are easy to forget to implement. If either method is omitted from the component implementation, then the page "forgets" the property values on subsequent requests, because either they were never written to disk, or were not loaded back into memory, or both.
Assuming that this is the root cause of your problem, the reason the problem does not occur when the component is inside a dialog with the default (false) value for keepComponents is because the default dialog behavior is to remove its children from the component tree entirely when the dialog is closed. This behavior is for performance reasons: there's theoretically no benefit to be gained from storing a server-side representation of components that only exist inside a dialog that the user is not currently interacting with. When the dialog is opened again, a new instance of each child component is created using the original property values. In this scenario, it wouldn't matter that your component isn't saving its state, because each time it's used, a new instance is created. But if the dialog is told to keep its children in the component tree, now the component must properly maintain its own state... otherwise its property values are discarded at the end of each request and subsequent requests are unaware of the previous values.
In summary, yes, the data you're displaying should be cached in a bean (or data source) if the data is unlikely to change enough between requests to justify obtaining the data again during every single event. But the reason for the specific behavior you're describing is most likely because your component implementation is not properly maintaining its own state.
# student.rb
has_and_belongs_to_many :courses
# course.rb
has_and_belongs_to_many :students
I'm trying to create a scope in the students model that will check if they are enrolled in a course.
The best I've come up with is:
scope :unenrolled, where(Student.courses.count => 0)
But then I get the error message
undefined method `courses'
Anybody offer any suggestions?
Alright then. So here's your code:
scope :unenrolled, where(Student.courses.count => 0)
The first problem here is the thing that's causing the error: You're calling the instance method courses on the class Student. As the name implies, you can only call an instance method on an instance of a class, not on the class itself. For example:
jim = Student.find(123)
jims_courses = jim.courses
But here's the kicker: When you call scope you're in the class context, i.e. the code isn't inside an instance method, so it gets called when your model is first declared. There's no instance at that time so you can't just call courses like you would from within one of Student's instance methods.
But that's kind of moot since you've slightly misunderstood how where works. The argument(s) you give to where are supposed to be conditions that correspond to what you would put after WHERE in an SQL query. For example where(:eye_color => 'brown') will be turned into an SQL WHERE clause like WHERE eye_color = 'brown'. :eye_color => 'brown' is just a Hash with the key :eye_color whose value is 'brown'. Calling a function on the left side of => doesn't make sense unless the function returns the name of a column/attribute in your model that ActiveRecord will understand.
So now let's figure out what you should do. If you were writing an SQL query it would look something like this:
SELECT `students`.*, COUNT(`courses_students`.*) AS `courses_count`
FROM `students`
JOIN `courses_students` ON `students`.`id` = `courses_students`.`student_id`
WHERE `courses_count` = '0'
GROUP BY `courses_students`.`student_id`;
This translates roughly to an ActiveRecord query like this:
Student.joins(:courses). // AR automatically joins courses though courses_students
select('students., COUNT(courses.) AS courses_count').
where('courses_count = 0').
group('id')
And you can plunk that directly into your scope:
scope :unenrolled, joins(:courses).
select('students.*, COUNT(courses.*) AS courses_count').
where('courses_count = 0').
group('courses.course_id')
Note: These queries are a bit off-the-cuff and may require a bit of tweaking. The easiest way to build complicated ActiveRecord queries is by entering them directly into the Rails console until you get the results you want.
Hope that's helpful!