I'm reading the source of activejdbc, found these methods in ModelInstrumentation.
public void instrument(CtClass modelClass) throws Exception {
addDelegates(modelClass);
CtMethod m = CtNewMethod.make("public static String getClassName() { return \"" + modelClass.getName()
+ "\"; }", modelClass);
CtMethod getClassNameMethod = modelClass.getDeclaredMethod("getClassName");
modelClass.removeMethod(getClassNameMethod);
modelClass.addMethod(m);
}
CtClass modelClass = ClassPool.getDefault().get("org.javalite.activejdbc.Model");
private void addDelegates(CtClass target) throws NotFoundException, CannotCompileException {
CtMethod[] modelMethods = modelClass.getDeclaredMethods();
CtMethod[] targetMethods = target.getDeclaredMethods();
for (CtMethod method : modelMethods) {
if (Modifier.PRIVATE == method.getModifiers()) {
continue;
}
CtMethod newMethod = CtNewMethod.delegator(method, target);
if (!targetHasMethod(targetMethods, newMethod)) {
target.addMethod(newMethod);
} else {
System.out.println("Detected method: " + newMethod.getName() + ", skipping delegate.");
}
}
}
This class is used to enhance a model class, the first one instrument will firstly delegate all non-private methods from org.javalite.activejdbc.Model to its child model class, which means it will add such methods to the child:
public X f(...) {
return super.f(...);
}
I don't understand why it does this, since we can invoke these methods even if there is no delegates.
Explanation of this can be found in this discussion:
https://groups.google.com/forum/#!topic/activejdbc-group/l6KNBi5EPc0
Basically, the main problem is that the methods in the Model class that we need in a child class are static. Static classes in Java are not inherited. This means that when you do this:
Person.where(...)
You will be executing the method Model.where(), not the Person.where(), hence the framework would have no idea what table to query.
ActiveJDBC forces Model methods into child methods in order to at run time determine what table to go to for data.
Related
I've got a top-level Controller object that is holding a reference to three objects (MyObject). I'd like to position these precisely on the page at any time, but I would like each object to also be editable, and I'm not really sure how to do that.
So far, I've got a class that extends ItemFragment and displays my individual items, like this:
class MyObjectFragment(o: MyObject) : ItemFragment<MyObject>() {
override val root = hbox {
...
}
}
Meanwhile, I have a top-level View with a reference to my controller, like this:
class TopLevelView : View() {
val controller = TopLevelController()
override val root = hbox {
add(MyObjectFragment(controller.myObject1))
...
add(MyObjectFragment(controller.myObject2))
...
add(MyObjectFragment(controller.myObject3))
}
}
And right now, all I have for the top level controller is this:
class TopLevelController() : Controller() {
val myObject1 = MyObject()
val myObject2 = MyObject()
val myObject3 = MyObject()
}
I'm trying to figure out what I need to do to wrap these objects as observable values. My first attempt was to add something like this to the init method of MyObjectFragment:
class MyObjectFragment(o: MyObject) : ItemFragment<MyObject>() {
init {
itemProperty.bind(o)
}
...
}
However, that method only takes an ObservableValue<MyObject>. What is the best way to get that to tie all of this together?
You can create an observable list of your objects like so:
class TopLevelController() : Controller() {
val myObjects = FXCollections.observableArrayList<MyObject>(MyObject(), MyObject(), MyObject())
}
Then in your TopLevelView, you can bind this list to a layout node's children property, and inflate the proper Fragment for each object:
class TopLevelView : View() {
val controller = TopLevelController()
override val root = hbox {
bindChildren(controller.myObjects) {
MyObjectFragment(it).root
}
}
}
I'll admit your requirements seem a little vague to me without more information. It'd be helpful to know more of what you want from the item fragments. Are they going to be in a list view or table? Or something more dynamic? And how exactly would they be editing? Would there be a save button or would you expect any input to commit those changes immediately?
import tornadofx.*
class MyObject() {
//val someProperty = SimpleObjectProperty<Something>()
//var some by someProperty
}
class MyObjectModel(myObject: MyObject? = null) : ItemViewModel<MyObject>(myObject) {
//val someBinding = bind(MyObject::someProperty)
}
class MyObjectFragment : ItemFragment<MyObject>() {
val model: MyObjectModel by inject()
override val root = hbox {
label("This is an MyObject Fragment")
//you would bind some control to the model binding in here. For example:
//textfield(model.someBinding)
}
init {
itemProperty.value = model.item
model.bindTo(this)
}
}
class TopLevelController : Controller() {
val myObject1 = MyObject()
val myObject2 = MyObject()
val myObject3 = MyObject()
}
class TopLevelView : View() {
val controller: TopLevelController by inject()
override val root = vbox {
add(setUpObjectFragment(controller.myObject1))
add(setUpObjectFragment(controller.myObject2))
add(setUpObjectFragment(controller.myObject3))
}
fun setUpObjectFragment(obj: MyObject) = find<MyObjectFragment>(Scope(MyObjectModel(obj)))
}
It also seems you're new and are missing a lot of key concepts to utilize from TornadoFX. Using find for instance, is really important for Fragments and Views so they have the proper life cycle.
Then there's Scopes which help with being able to call certain Components with injection.
And finally, there are Model classes, most importantly ItemViewModel which gives you the most functionality with editing, like being able to rollback and commit changes as well as to mark properties as required and add validate filters.
If this isn't a satisfactory solution, please give us more information on what you want, as I might be able to provide a more elegant and concise solution. If these concepts are confusing, please look at Edvin's guide.
I'm trying to implement optimistic concurrency checking in Hazelcast as described here. I've set my MapConfigs to use InMemoryFormat.OBJECT and I've added a version field to my BaseEntity with equals() and hashCode() defined like this:
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
BaseEntity that = (BaseEntity) o;
return getId().equals(that.getId()) && getVersion() == that.getVersion();
}
#Override
public int hashCode() {
return (int) (getId().hashCode() + version);
}
In my BaseService I've replaced the map.replace(id, entity) with the 3 arg version like this:
instance.incrementVersion();
if (getTransactionalMap().replace(instance.getId(), existing, instance)) {
// do some stuff here
} else {
throw new OptimisticConcurrencyServiceException(
"Could not replace existing " + existing.getEntityId() + " with version " + existing.getVersion());
}
The problem I'm having is that my MapStore isn't called on updates. In one transaction I create an object and store it to the map via my BaseService.create() method (and this calls my MapStore) then I do some other things with it and call service.update() which ends up calling my doUpdate() method above. This update never ends up getting to my MapStore so the value is never persisted. When I was using the 2 arg version of the replace method (replace(id, entity)) these changes did get to the MapStore and thus were persisted. What's the difference, and how to I get this to work?
EDIT: Adding the update() method:
public void update(NestupSecurityContext context, String id, #Validated T entity) throws ServiceException {
T existing = getOne(context, id);
if (existing != null) {
if (existing.equals(entity)) {
T copy;
try {
copy = (T) existing.clone();
} catch (CloneNotSupportedException e) {
//shouldn't be possible
throw new ServiceException(e);
}
copy.copyFrom(entity);
doUpdate(context, existing, copy);
} else {
throw new OptimisticConcurrencyServiceException(
entity.getEntityId() + " is out of date! Current version is " + existing.getVersion() + ", trying to save version " + entity.getVersion());
}
}
}
notes:
the equals() checks the version, as above
the copyFrom() is because these entities mostly come from REST endpoints and not all values can be set via the REST endpoint. The copyFrom() copies just the editable values, including the version field which has to be carried along when the client calls to get the entity before updating it.
the clone() gives us a clean copy of what this transaction reads as the base value
This was a problem with my copyFrom() not calling the parent class to copy the version. I also needed to make my update() methods return the updated instance (which won't be the same as the original instance) so if code needed to keep using the object it could update its reference with the updated object.
I need to change a function that accepts one Expression with one property inside and give it the ability to work with 2 properties at least.
I have the following base class that contains nested ElementHelper class
public class DomainObjectViewModel<TModel> where TModel : DomainObject
{
public class ElementHelper
{
public static void Create<T1>(TModel model, Expression<Func<TModel, T1>> expression)
{
var getPropertyInfo = GetPropertyInfo(expression);
//Do cool stuff
}
private static PropertyInfo GetPropertyInfo<T1>(Expression<Func<TModel, T1>> propertyExpression)
{
return (PropertyInfo)((MemberExpression)propertyExpression.Body).Member;
}
}
}
-ElementHelper class contains a Create function that gets the propertyInfo of the expression and only works if you pass one property in the expression.
Then I have the following inherited class that uses the helper function in the constructor.
public class ProductViewModel : DomainObjectViewModel<ProductEditViewModel>
{
public ProductViewModel(ProductEditViewModel model)
{
//It works for one property in the Expression
ElementHelper.Create(model, x => x.LaunchDate);
//Give the ability to pass multiple paramenters in the expression
ElementHelper.Create(model, x => new { x.LaunchDate, x.ApplyLaunchDateChanges });
}
}
I think I can use NewExpression (new { x.LaunchDate, x.ApplyLaunchDateChanges }) in order to pass it a collection of properties, but I cannot make it work.
Would you use same approach?
How you can split the passed Expression so you can get the propertyinfo of each properties found in the NewExpression object?
Well, since ElementHelper.GetPropertyInfo is your own method, you can decide what is allowed to pass, and then handle it appropriately inside that method.
Currently you handle only MemberExpression, so that's why it works only with single property accessor. If you want to be able to pass new { ... }, you need to add support for NewExpression like this:
private static IEnumerable<PropertyInfo> GetPropertyInfo<T1>(Expression<Func<TModel, T1>> propertyExpression)
{
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression != null)
return Enumerable.Repeat((PropertyInfo)memberExpression.Member, 1);
var newExpression = propertyExpression.Body as NewExpression;
if (newExpression != null)
return newExpression.Arguments.Select(item => (PropertyInfo)((MemberExpression)item).Member);
return Enumerable.Empty<PropertyInfo>(); // or throw exception
}
I'm using SPMetal in order to generate entity classes for my sharepoint site and I'm not exactly sure what the best practice is to use when there are multiple content types for a single list. For instance I have a task list that contains 2 content types and I'm defining them via the config file for SPMetal. Here is my definition...
<List Member="Tasks" Name="Tasks">
<ContentType Class="LegalReview" Name="LegalReviewContent"/>
<ContentType Class="Approval" Name="ApprovalContent"/>
</List>
This seems to work pretty well in that the generated objects do inherit from WorkflowTask but the generated type for the data context is a List of WorkflowTask. So when I do a query I get back a WorkflowTask object instead of a LegalReview or Approval object. How do I make it return an object of the correct type?
[Microsoft.SharePoint.Linq.ListAttribute(Name="Tasks")]
public Microsoft.SharePoint.Linq.EntityList<WorkflowTask> Tasks {
get {
return this.GetList<WorkflowTask>("Tasks");
}
}
UPDATE
Thanks for getting back to me. I'm not sure how I recreate the type based on the SPListItem and would appreciate any feedback.
ContractManagementDataContext context = new ContractManagementDataContext(_url);
WorkflowTask task = context.Tasks.FirstOrDefault(t => t.Id ==5);
Approval a = new Approval(task.item);
public partial class Approval{
public Approval(SPListItem item){
//Set all properties here for workflowtask and approval type?
//Wouldn't there be issues since it isn't attached to the datacontext?
}
public String SomeProperty{
get{ //get from list item};
set{ //set to list item};
}
Linq2SharePoint will always return an object of the first common base ContentType for all the ContentTypes in the list. This is not only because a base type of some description must be used to combine the different ContentTypes in code but also it will then only map the fields that should definitely exist on all ContentTypes in the list. It is however possible to get access to the underlying SPListItem returned by L2SP and thus from that determine the ContentType and down cast the item.
As part of a custom repository layer that is generated from T4 templates we have a partial addition to the Item class generated by SPMetal which implements ICustomMapping to get the data not usually available on the L2SP entities. A simplified version is below which just gets the ContentType and ModifiedDate to show the methodology; though the full class we use also maps Modified By, Created Date/By, Attachments, Version, Path etc, the principle is the same for all.
public partial class Item : ICustomMapping
{
private SPListItem _SPListItem;
public SPListItem SPListItem
{
get { return _SPListItem; }
set { _SPListItem = value; }
}
public string ContentTypeId { get; internal set; }
public DateTime Modified { get; internal set; }
public virtual void MapFrom(object listItem)
{
SPListItem item = (SPListItem)listItem;
this.SPListItem = item;
this.ContentTypeId = item.ContentTypeId.ToString();
this.Modified = (DateTime)item["Modified"];
}
public virtual void MapTo(object listItem)
{
SPListItem item = (SPListItem)listItem;
item["Modified"] = this.Modified == DateTime.MinValue ? this.Modified = DateTime.Now : this.Modified;
}
public virtual void Resolve(RefreshMode mode, object originalListItem, object databaseObject)
{
SPListItem originalItem = (SPListItem)originalListItem;
SPListItem databaseItem = (SPListItem)databaseObject;
DateTime originalModifiedValue = (DateTime)originalItem["Modified"];
DateTime dbModifiedValue = (DateTime)databaseItem["Modified"];
string originalContentTypeIdValue = originalItem.ContentTypeId.ToString();
string dbContentTypeIdValue = databaseItem.ContentTypeId.ToString();
switch(mode)
{
case RefreshMode.OverwriteCurrentValues:
this.Modified = dbModifiedValue;
this.ContentTypeId = dbContentTypeIdValue;
break;
case RefreshMode.KeepCurrentValues:
databaseItem["Modified"] = this.Modified;
break;
case RefreshMode.KeepChanges:
if (this.Modified != originalModifiedValue)
{
databaseItem["Modified"] = this.Modified;
}
else if (this.Modified == originalModifiedValue && this.Modified != dbModifiedValue)
{
this.Modified = dbModifiedValue;
}
if (this.ContentTypeId != originalContentTypeIdValue)
{
throw new InvalidOperationException("You cannot change the ContentTypeId directly");
}
else if (this.ContentTypeId == originalContentTypeIdValue && this.ContentTypeId != dbContentTypeIdValue)
{
this.ContentTypeId = dbContentTypeIdValue;
}
break;
}
}
}
Once you have the ContentType and the underlying SPListItem available on your L2SP entity it is simply a matter of writing a method which returns an instance of the derived ContentType entity from a combination of the values of the base type and the extra data for the missing fields from the SPListItem.
UPDATE: I don't actually have an example converter class as we don't use the above mapping extension to Item in this way. However I could imagine something like this would work:
public static class EntityConverter
{
public static Approval ToApproval(WorkflowTask wft)
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = wft.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = wft.SPListItem["field-name"];
return a;
}
}
Or you could put a method on a partial instance of WorkflowTask to return an Approval object.
public partial class WorkflowTask
{
public Approval ToApproval()
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = this.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = this.SPListItem["field-name"];
return a;
}
public LegalReview ToLegalReview()
{
// Create and return LegalReview as for Approval
}
}
In either situation you would need to determine the method to call to get the derived type from the ContentTypeId property of the WorkflowTask. This is the sort of code I would normally want to generate in one form or another as it will be pretty repetitive but that is a bit off-topic.
I'm trying to call a method from another class and from what I've gathered, the method I'm trying to call is an instance method. I've gathered that, that means it uses instance variables of an object. Is there an easy way to call this method?
This is the main method,
public void main()
{
Test.testPetOwner();
}
And this is the method I'm trying to call in a class called "Test"
public void testPetOwner()
{
String petName;
String species;
String hairCondition;
String posture;
testCompetitor();
PetOwner petOwner1 = new PetOwner();
System.out.println("What is the pet's name?");
petName = Genio.getString();
petOwner1.setPetName(petName);
System.out.println("What is the species of the pet?");
species = Genio.getString();
petOwner1.setSpecies(species);
System.out.println("What is the hair condition of the pet?");
hairCondition = Genio.getString();
petOwner1.setHairCondition(hairCondition);
System.out.println("How is the pet's posture?");
posture = Genio.getString();
petOwner1.setPosture(posture);
}
public void main()
{
Test t = new Test();
t.testPetOwner();
}
If we try to access an instance method from a static context , compiler has now way to guess which instance method ( variable for which object ), you are referring too. Though you can always access it using object reference.