I am attempting to provide a Dataview delegate overide to the UnionDeductions view in PRCalculationEngine.cs
I note that this View does NOT have a defined dataview delegate in the Base graph - and the declaration is a bit 'different' in that is uses a BQL Fluent class.
Is this even possible to introduce a data view delegate in an extension
If so, Is there a different way of declaring the delegate ?
The business case is that the client needs to modify the Amount of the union deduction based on certain Employee attributes (length of service etc) and needs to dynamically modify the amount.
Due to the private and protected access of the GetBenefits and CalculateRegularBenefitNominalAmount methods, the only way I see to do this is to over-ride the dataview delegate and alter the Deduction/Benefit amounts prior to the calculation of the Benefit/Deduction amount...
public partial class PRCalculationEngine : PXGraph
{.....
public UnionDeductionQuery UnionDeductions;
...}
When I attempt to define a dataview delegate for this view in an Extension - I cannot get the dataview delegate to 'fire'
ie The code always just runs the .Select on the Base view but does not execute the delegate.
This is the core of the extension code
public class PRCalculationEngine_Ext1ESP : PXGraphExtension
{
public static bool IsActive() { return PXAccess.FeatureInstalled<FeaturesSet.payrollModule>(); }
#region Select Overrides
public PRCE.UnionDeductionQuery UnionDeductions;
protected System.Collections.IEnumerable unionDeductions()
{
foreach (PXResult<PREarningDetail, PRDeductionAndBenefitUnionPackage, PRDeductCode, EPEarningType> result in
UnionDeductions.Select())
{
// modify the package amount here...
yield return result;
}
}
#endregion
}
This is how the view is being called in the Base Graph
foreach (IGrouping<int?, PXResult<PREarningDetail, PRDeductionAndBenefitUnionPackage, PRDeductCode, EPEarningType>> resultGroup in UnionDeductions.Select(deductionCode.CodeID)
.Select(x => (PXResult<PREarningDetail, PRDeductionAndBenefitUnionPackage, PRDeductCode, EPEarningType>)x)
.GroupBy(x => ((PREarningDetail)x).RecordID))
{
Any advice or observations would be appreciated.
If the requirement is to overwrite the logic of the base dataview delegate which also references other protected methods, try if this helps:
First create an extension of the base class as follows with the PXProtectedAccess attribute and the methods that you want to override:
[PXProtectedAccess]
public abstract class PRCalculationEngine_FirstExt : PXGraphExtension<PRCalculationEngine>
{
[PXProtectedAccess]
public abstract DedBenAmount CalculateRegularBenefitNominalAmount(
PRDeductCode deductCode,
PREmployeeDeduct employeeDeduct,
PRPaymentDeduct paymentDeduct);
}
Then create a second extension (your actual graph extension) inheriting from both the base class and the first extension you created above.
public class PRCalculationEngine_Extension : PXGraphExtension<PRCalculationEngine_FirstExt, PRCalculationEngine>
{
// Here declare the view, write the PXOverride method, and access the protected methods of the base graph by referencing those as Base1.CalculateRegularBenefitNominalAmount()
}
Note that the above snippets are just to give an indication. I have not really worked on the PRCalculationEngine or tested that code but had done similar changes on a different graph to override the dataview delegate. Let me know if it helps. Thank you.
Related
I use this code in my application and I find it very ugly.
Is there a smart way of doing this?
for (final ApplicationCategories applicationCategorie : applicationCategories) {
if (applicationCategorie == ApplicationCategories.PROJECTS) {
// invoke right method
} else if (applicationCategorie == ApplicationCategories.CALENDAR) {
// ...
} else if (applicationCategorie == ApplicationCategories.COMMUNICATION) {
} else if (applicationCategorie == ApplicationCategories.CONTACTS) {
} else if (applicationCategorie == ApplicationCategories.DOCUMENTS) {
} else if (applicationCategorie == ApplicationCategories.WORKINGBOOK) {
}
}
My aim is to handle all application categorie enums which contained into the enum list.
The least you can do is to declare the method that handles the behaviour dependent to the enum inside ApplicationCategories. In this way, if you will add a new value to the enum, you will only to change the code relative to enum.
In this way, your code adheres to the Open Closed Principle, and so it is easier to maintain.
enum ApplicationCategories {
PROJECTS,
CALENDAR,
// And so on...
WORKINGBOOK;
public static void handle(ApplicationCategories category) {
switch (category) {
case PROJECTS:
// Code to handle projects
break;
case CALENDAR:
// Code to handle calendar
break;
// And so on
}
}
}
This solution is only feasable if you do not need any external information to handle the enum value.
Remember you can also add fields to enum values.
EDIT
You can also implement a Strategy design pattern if you need. First of all, define a strategy interface and some concrete implementations.
interface CategoryStrategy {
void handle(/* Some useful input*/);
}
class ProjectStrategy implements Strategy {
public void handle(/* Some useful input*/) {
// Do something related to projects...
}
}
class CalendarStrategy implements Strategy {
public void handle(/* Some useful input*/) {
// Do something related to calendars...
}
}
//...
Then, you can modify your enum in order to use the above strategy.
enum ApplicationCategories {
PROJECTS(new ProjectStrategy()),
CALENDAR(new CalendarStrategy()),
// And so on...
WORKINGBOOK(new WorkingBookStrategy());
private CategoryStrategy strategy;
ApplicationCategories(CategoryStrategy strategy) {
this.strategy = strategy;
}
public static void handle(ApplicationCategories category) {
category.strategy.handle(/* Some inputs */);
}
}
Clearly, the above code is only a sketch.
The design pattern you need is the Strategy.
Enums and violation of the Open/Closed Principle
The use of enums when you have to perform a different action for each defined value is a bad practice. As the software evolves, it is likely that you have to spread the if chain around different places. If you add a new enum value, you'll have to add a new if for that value in all these places. Since you may not even be able to find all the places where you have to include the new if, that is a source for bugs.
Such approach also violates the Open/Closed Principle (OCP). Just creating a method to handle each enum value doesn't make your code conformant to OCP. It will make the code more organised but doesn't change anything about the "if" issue.
Java 7 solution with Strategy Pattern
Using Java 7 or prior, you can define a ApplicationCategory interface that all categories will implement. This interface will provide a common method that each category will implement to perform the required actions for that category:
public interface ApplicationCategory {
boolean handle();
}
Usually your method should return something. Since I don't know what is your exact goal, I'm making the method to return just a boolean. It would indicate if the category was handled or not, just as an example.
Then you have to define a class implementing such an interface for each category you have. For instance:
public class CalendarCategory implements ApplicationCategory {
boolean handle(){
//the code to handle the Calendar category
return true;
}
}
public class CommunicationCategory implements ApplicationCategory {
boolean handle(){
//the code to handle the Communication category
return true;
}
}
Now you don't need the enum class and the handle method that was inside it needs to be moved elsewhere, that completely depends on your project. That handle method will be changed to:
public static void handle(ApplicationCategory category) {
//Insert here any code that may be executed,
//regardless of what category it is.
category.handle();
}
You don't need an enum anymore because any variable declared as ApplicationCategory just accepts an object that implements such an interface. If you use the enum together with the Strategy implementation, it will be yet required to change the enum class any time you add a new ApplicationCategory implementation, violating the OCP again.
If you use the Strategy pattern, you don't even need the enum anymore in this case.
Java 8 solution with functional programming and Strategy Pattern
You can more easily implement the Strategy pattern using functional programming and lambda expressions, and avoid the proliferation of class just to provide different implementations of a single method (the handle method in this case).
Since the handle method is not receiving any parameter and is retuning something, this description conforms to the Supplier functional interface. An excellent way to identify what kind of functional interface a method you are defining conforms to, it is studying the java.util.function package.
Once the type of functional interface is identified, we can create just a ApplicationCategory class (that in the Java 7 example was an interface) in a functional way, defining the previous handle method as an attribute of the Supplier type. You must define a setter for this handle attribute to enable changing the handle implementation. Defining a method as an attribute, you are enabling such a method implementation to be changed in runtime, providing a different but far simpler, easier and more maintainable implementation of the Strategy pattern.
If you need to use the category name somewhere, for instance to display it in a user interface, you could define an enum inside the ApplicationCategory class. However, there is no direct relation between the enum value and the handle provided. The enum works just as a tag for the category. It is like a "name" attribute in a Person class, that we usually just use to "tag" and print a person.
public class ApplicationCategory {
//insert all categories here
enum Type {CALENDAR, COMMUNNICATION}
/**
* The Supplier object that will handle this category object.
* It will supply (return) a boolean to indicate if the category
* was processed or not.
*/
private Supplier<Boolean> handler;
private Type type;
/**
* A constructor that will receive a Supplier defining how to
* handle the category that is being created.
*/
public ApplicationCategory(Type type, Supplier<Boolean> handler){
Objects.requireNonNull(type);
this.handler = handler;
setType(type);
}
/**
* Handle the category by calling the {#link Supplier#get()} method,
* that in turn returns a boolean.
*/
public boolean handle(){
return supplier.get();
}
public Type getType(){ return type; }
public final void setHandler(Supplier<Boolean> handler){
Objects.requiredNonNull(handler);
this.handler = handler;
}
}
If you give the behaviour that will handle the enum value at the enum constructor call, as suggested by the other answer provided here, then you don't have how to change the behaviour in runtime and it in fact doesn't conform to the Strategy pattern. Unless you really don't need that, you might implement in that way, but remember it violates the OCP.
How to use the Java 8 functional ApplicationCategory class
To instantiate a ApplicationCategory you have to provide the Type (an enum value) and the handler (that is a Supplier and can be given as a lambda expression). See the example below:
import static ApplicationCategory.CALENDAR;
public class Test {
public static void main(String args[]){
new Test();
}
public Test(){
ApplicationCategory cat = new ApplicationCategory(CALENDAR, this::calendarHandler);
System.out.println("Was " + cat + " handled? " + cat.handle());
}
private boolean calendarHandler(){
//the code required to handle the CALENDAR goes here
return true;
}
}
The this::calendarHandler instruction is a method reference to pass a "pointer" to the calendarHandler method. It is not calling the method (you can see that due to the use of :: instead of . and the lack of parenthesis), it is just defining what method has to be in fact called when the handle() method is called, as can be seen in System.out.println("Was " + cat + " handled? " + cat.handle());
By using this approach, it is possible to define different handlers for different instances of the same category or to use the same handler for a subset of categories.
Unlike other languages, Java provides facilities that specifically allow this sort of thing to be done in a safe object-oriented way.
Declare an abstract method on the enum, and then specific implementations for each enum constant. The compiler will then ensure that every constant has an implementation and nobody has to worry about missing a case somewhere as new values are added:
enum ApplicationCategories {
PROJECTS {
void handle() {
...
}
},
...
public abstract void handle();
}
Then, instead of calling some static handle(category), you just call category.handle()
I'm having trouble getting PEX to automatically cover methods calling Linq extension methods, such as Where() and Contains() in this example:
public class MyEntity
{
public int Id { get; set; }
}
public interface IWithQueryable
{
IQueryable<MyEntity> QueryableSet();
}
public class ConsumerOfIhaveIQueryable
{
private readonly IWithQueryable _withIQueryable;
public ConsumerOfIhaveIQueryable(IWithQueryable withIQueryable)
{
// <pex>
Contract.Requires<ArgumentNullException>(
withIQueryable != null, "withIQueryable");
// </pex>
_withIQueryable = withIQueryable;
}
public IEnumerable<MyEntity> GetEntitiesByIds(IEnumerable<int> ids)
{
Contract.Requires<ArgumentNullException>(ids != null, "ids");
// <pex>
Contract.Assert
(this._withIQueryable.QueryableSet() != (IQueryable<MyEntity>)null);
// </pex>
IEnumerable<MyEntity> entities =
_withIQueryable.QueryableSet().Where(
entity => ids.Contains(entity.Id));
if (entities.Count() != ids.Count())
{
return null;
}
return entities;
}
}
[PexClass(typeof(ConsumerOfIhaveIQueryable))]
[PexAllowedExceptionFromTypeUnderTest(typeof(InvalidOperationException))]
[PexAllowedExceptionFromTypeUnderTest(typeof(ArgumentException), AcceptExceptionSubtypes = true)]
[TestClass]
public partial class ConsumerOfIhaveIQueryableTest
{
[PexMethod]
public IEnumerable<MyEntity> GetEntitiesByIds(
[PexAssumeUnderTest]ConsumerOfIhaveIQueryable target,
int[] ids)
{
var result = target.GetEntitiesByIds(ids);
PexAssert.IsTrue(result.Count() == ids.Length);
return result;
}
}
When I'm running PEX exploration on this PexMethod I'm seeing the following problems:
I keep getting the same exception and PEX keeps suggesting the same "invariant" fix in the form of the Contract.Assert that you see in the // region:
I believe the problem is somehow related to how Pex relates to Linq but I'm not sure
--- Description
failing test: ArgumentNullException, Value cannot be null.
Parameter name: source
[TestMethod]
[PexGeneratedBy(typeof(ConsumerOfIhaveIQueryableTest))]
[PexRaisedException(typeof(ArgumentNullException))]
public void GetEntitiesByIdsThrowsArgumentNullException385()
{
using (PexChooseBehavedBehavior.Setup())
{
SIWithQueryable sIWithQueryable;
ConsumerOfIhaveIQueryable consumerOfIhaveIQueryable;
IEnumerable<MyEntity> iEnumerable;
sIWithQueryable = new SIWithQueryable();
consumerOfIhaveIQueryable =
ConsumerOfIhaveIQueryableFactory.Create((IWithQueryable)sIWithQueryable);
int[] ints = new int[0];
iEnumerable = this.GetEntitiesByIds(consumerOfIhaveIQueryable, ints);
}
}
--- Exception details
System.ArgumentNullException: Value cannot be null.
Parameter name: source at System.Linq.IQueryable'1 System.Linq.Queryable.Where(System.Linq.IQueryable'1 source, System.Linq.Expressions.Expression'1> predicate)
c:\users\moran\documents\visual studio 2010\Projects\PexTuts\PexIQueryable\PexIQueryable\ConsumerOfIhaveIQueryable.cs(29): at System.Collections.Generic.IEnumerable'1 PexIQueryable.ConsumerOfIhaveIQueryable.GetEntitiesByIds(System.Collections.Generic.IEnumerable`1 ids)
c:\users\moran\documents\visual studio 2010\Projects\PexTuts\PexIQueryable\PexIQueryable.Tests\ConsumerOfIhaveIQueryableTest.cs(34): at System.Collections.Generic.IEnumerable'1 PexIQueryable.ConsumerOfIhaveIQueryableTest.GetEntitiesByIds(PexIQueryable.ConsumerOfIhaveIQueryable target, System.Int32[] ids)
I can't get PEX to generate relevant inputs. As you can see, I tried to "help" it by adding a PexAssert and a branch in my code, but this branch is never covered, even though it should be relatively simple to generate a code that would walk that path. PEX only tries to pass null or an empty array as the list of Ids (I read somewhere that it is easier for PEX to work with arrays (int[]) rather than IEnumerable.
Would love to get some comments on this...
BTW, this is my first SO post, Hope I didn't spam with too much code and info.
Moran
After some time setting up the code for this, I've made a few assumptions. I'm assuming that you're stubbing the IWithQueryable via a Moles stub and also that the NullArgumentException occurs when you remove the Contract assertion that the QueryableSet() method doesn't return null.
As for the code, IMO the more code the better, as long as it's relevant- far better to have too much than too little to go on, so that's fine. As above, do try to make clear all the assumptions in the code (e.g. the Moles stubbing (as there's different ways to achieve this and it's something one has to assume).
I'm not 100% sure what you're asking. The code is failing because the stubbed IWithQueryable object doesn't have an implmementation for the QueryableSet() method and that method returns null. The PexAssert here won't help it figure out how to create a LINQ provider, which is what you're asking it to do. The PexChooseBehavedBehavior.Setup() simply replaces any calls to delegates on the Moles stubs (which don't have a custom delegate) with the default behaviour which is default(T), so that's why the source is null- the QueryableSet() is initialised to null.
You can solve this in a few ways (at least in the sense of providing a way of creating the QueryableSet() method). You can create a factory method to generate either the whole SIWithQueryable, or just the QueryableSet delegate. This is something that Pex suggests (however, with me it got the types and namespaces muddled-up). For instance:
/// <summary>A factory for Microsoft.Moles.Framework.MolesDelegates+Func`1[System.Linq.IQueryable`1[StackOverflow.Q9968801.MyEntity]] instances</summary>
public static partial class MolesDelegatesFactory
{
/// <summary>A factory for Microsoft.Moles.Framework.MolesDelegates+Func`1[System.Linq.IQueryable`1[StackOverflow.Q9968801.MyEntity]] instances</summary>
[PexFactoryMethod(typeof(MolesDelegates.Func<IQueryable<MyEntity>>))]
public static MolesDelegates.Func<IQueryable<MyEntity>> CreateFunc()
{
throw new InvalidOperationException();
// TODO: Edit factory method of Func`1<IQueryable`1<MyEntity>>
// This method should be able to configure the object in all possible ways.
// Add as many parameters as needed,
// and assign their values to each field by using the API.
}
/// <summary>A factory for Microsoft.Moles.Framework.MolesDelegates+Func`1[System.Linq.IQueryable`1[StackOverflow.Q9968801.MyEntity]] instances</summary>
[PexFactoryMethod(typeof(SIWithQueryable))]
public static SIWithQueryable Create()
{
var siWithQueryable = new SIWithQueryable();
siWithQueryable.QueryableSet = () => { throw new InvalidOperationException(); };
return siWithQueryable;
// TODO: Edit factory method of Func`1<IQueryable`1<MyEntity>>
// This method should be able to configure the object in all possible ways.
// Add as many parameters as needed,
// and assign their values to each field by using the API.
}
}
and then hook it up to the test method with one of the two lines assigning sIWithQueryable:
[TestMethod]
[PexGeneratedBy(typeof(ConsumerOfIhaveIQueryableTest))]
public void GetEntitiesByIdsThrowsArgumentNullException678()
{
SIWithQueryable sIWithQueryable;
// Either this for the whole object.
sIWithQueryable = MolesDelegatesFactory.Create();
// Or this for just that delegate.
sIWithQueryable = new SIWithQueryable();
sIWithQueryable.QueryableSet = MolesDelegatesFactory.CreateFunc();
ConsumerOfIhaveIQueryable consumerOfIhaveIQueryable;
IEnumerable<MyEntity> iEnumerable;
consumerOfIhaveIQueryable = ConsumerOfIhaveIQueryableFactory.Create((IWithQueryable) sIWithQueryable);
int[] ints = new int[0];
iEnumerable = this.GetEntitiesByIds(consumerOfIhaveIQueryable, ints);
}
This will then call your factory methods when creating the stub for IWithQueryable. This is still a problem, as regenerating the explorations will wipe out the stub setup.
If you provide the parameterless factory method to create the stub (MolesDelegatesFactory.CreateFunc()), then Pex will know about this and generate the tests to use it. So, it will correctly manage the behaviour across test regenerations. Unfortuantely, Pex suggests creating this delegate as a factory method- however, it is never called, the default implementation is always used, it seems one has to mock the parent type.
However, I'm wondering why you're creating an interface IWithQueryable that simple wraps another, and also, what you expect to do with the IQueryable. In order to do anything very useful, you'll have a lot of work going on to deal with the IQueryable interface - the Provider and Expression mainly, you'll pretty-much have to write a mock query provider, which will not be easy.
I'm trying to implement a GridBoundColumn for filtering as described in this Telerik demo.
The example queries the database directly using SqlDataAdapter, but I want to use an existing class elsewhere in my project, and configure the DataSource of the filter RadComboBox in the RadGrid to use the LINQ data context common to the rest of my project.
namespace MyProject.DataLib
{
// Data context lives here.
}
namespace MyProject.UI
{
public partial class MyUI : PageBase
{
public class rgcFilterColumn : GridBoundColumn
{
...
protected void list_ItemsRequested(object o, RadComboBoxItemsRequestedEventArgs e)
{
using (MyProject.DataLib = new DataLib(CurrentUser)) // error CurrentUser
{
((RadComboBox)o).DataTextField = DataField;
((RadComboBox)o).DataValueField = DataField;
((RadComboBox)o).DataSource = ???; // LINQ would go here...?
((RadComboBox)o).DataBind();
}
}
}
}
}
The user defined by CurrentUser has the necessary credentials, however when I try to do this (which I know is wrong):
Cannot access non-static property 'CurrentUser' in static context.
What would be the best way to accomplish what I want here, as well as clarify my incomplete understanding of why I can't simply talk to my existing data context?
Found the solution, should've just looked around more closely.
I'm trying to write a generic method parameter validation functionality that can be chained (fluent interface) to attach more and more validations/checks like:
public void SomeMethod(User user, string description)
{
ParameterHelper
.Create(() => user)
.RejectNull();
ParameterHelper
.Create(() => description)
.RejectNull()
.RejectEmptyString();
// now this would be luxurious
ParameterHelper
.Create(() => new { user = user, desc = description })
.RejectNull(o => o.user)
.RejectNull(o => o.desc)
.RejectEmptyString(o => o.desc);
}
I would like to use this helper class to test method parameters for certain values before using them (most of the time null will be tested).
Current state of affairs
I first started writing static helper class without the Create() method like:
public static class ParameterHelper
{
public static void RejectNull(Expression<Func<T>> expr)
{
if (expr.Compile()().Equals(default(T)))
{
MemberExpression param = (MemberExpression)expr.Body;
throw new ArgumentNullException(param.Member.Name);
}
}
}
But this doesn't allow chaining. That's why I created the Create() method that would return something that can be used by chained extension methods.
The problem
I would like to avoid multiple Compile() calls, so basically my Create() method should return Func<T> and reject methods should be extension methods of Func<T>.
If my Create() does return Func<T> I don't get the chance to read parameter names that should be supplied to various exceptions (using MemberExpression).
If I return Expression<Func<T>> instead I will have to call Compile() in each Reject extension method.
Questions
Is there a C# library that already does this kind of chaining?
If not, what do you suggest how this should be done? Any examples from the web would be warmly welcome.
Additional note
I should point out that complex/long validation invocation code is not an option here, because my current validation is done like:
if (user == null)
{
throw new ArgumentNullException("user");
}
or
if (string.IsNullOrEmpty(description))
{
throw new ArgumentNullException("description");
}
Which has two major drawbacks:
I repeat the same lines of code over and over
it uses magic strings
So validation should be done with a one liner per check as described above in the desired scenario.
There is a simple way to implement such a fluent interface. Your 'ParameterHelper.Create' method should return an instance of some class (this class is named Requirements below). This instance should hold the expression which was passed to Create. Also this class should have Require... instance methods which will validate expression and return this. Requirements class can be a private class inside ParameterHelper. I would also introduce an interface for this requirements chain (this interface is named IRequirements below. Sample:
public static class ParameterHelper
{
public static IRequirements Create<T>(Expression<Func<T>> expression)
{
return new Requirements{ Expression = expression };
}
private class Requirements<T> : IRequirements
{
public readonly Expression<Func<T>> Expression { get; set; }
public IRequirements RejectNull()
{
if (Expression .Compile()().Equals(default(T)))
{
MemberExpression param = (MemberExpression)Expression.Body;
throw new ArgumentNullException(param.Member.Name);
}
return this;
}
// other Require... methods implemented in the same way
}
}
public interface IRequirements
{
IRequirements RejectNull();
}
This approach will allow you implementing your luxurious solution - you just need to add a corresponding parameters to Reject... methods. Also you will probably need to make IRequirements interface generic.
Robert,
I have a library that solves this problem. It is called Bytes2you.Validation (Project). It is fast, extensible, intuitive and easy-to-use C# library providing fluent APIs for argument validation.
It focuses exactly on the problem that you want to solve, but does not use expressions. This is so, because they are a lot slower than just passing the argument name. For a library like that, that is designed to be used everywhere the performance is one of the most critical features.
For example:
Guard.WhenArgument(stringArgument,"stringArgument").IsNullOrEmpty().IsEqual("xxx").Throw();
// Which means - when stringArgument is null or empty OR is equal to "xxx" we will throw exception. If it is null, we will throw ArgumentNullException. If it is equal to "xxx", we will throw ArgumentException.
Hey there! I'm relatively new to both GWT and java programming (or OOP for that matter), so apologies for the beginner questions/mistakes in advance. I've been trying to create some kind of observer pattern, but the development mode console keeps dropping error messages and sadly, they're far from helpful.
So here's what I'm trying to achieve:
- I've got the model that consists of the class Country, and stores a value called Influence.
- The view is the class called CountryDisplay. It's a GWT widget that should always display the current influence of a given country.
public class Country {
private int influece;
private CountryDisplay display;
public Country() {
influence = 0;
}
public void setDisplay(CountryDisplay display) //...
public int getInfluence() //...
public void setInfluence(int value) {
influence = value;
display.update();
}
}
public class CountryDisplay {
private Country country;
public CountryDisplay (Country country) {
//GWT widget creating stuff
this.country = country;
}
public void update() {
//InfluenceCounter is a simple Label
InfluenceCounter.setText(Integer.toString(country.getInfluence()));
}
}
Then in the EntryPoint class I do something like this:
Country italy = new Country();
CountryDisplay italyDisplay = new CountryDisplay(italy);
italy.setDisplay(italyDisplay);
RootPanel.get("nameFieldContainer").add(italyDisplay);
italy.setInfluence(3);
The development console indicated that it had a problem with the line "display.update();" in class Country. My first guess was that the problem was that the display was not initiated, so I created an interface for it, and in the Country constructor I created an empty, new display, that would later be overwritten.
public Country() {
influence = 0;
display = new DisplayInterface() {
public void update() {}
}
}
But I had no luck this way either. I guess this kind of cross-referencing is not allowed? I mean that the view has the model as a variable and vice versa.
When calling a method on the view individually (like:
italy.setInfluence(3);
italyDisplay.displayTheCurrentValue();
) it works, so the problem is definitely in the observer logic.
If I understand correctly, your are trying to "bind" user interface elements (your view class CountryDisplay) to data (the model class Country). "Bind" in the sense that if you change the model data (for example, call italy.setInfluence(10)) then the view would automatically update itself to reflect the change. And if your view provided an editor, you want the "binding" also to work in the other direction.
There are several frameworks out there that achieve this, see for example the post Best data binding solution for GWT. I have used GWT Pectin and there is the GWT Editors framework (which I have not yet used myself as it is relatively new).
Looking at your code, I feel you might want to more clearly separate the model from the view: your model class (Country) should not know about the view class, that is, it should not store a reference to CountryDisplay.