Make attributes mandatory for Groovy Class - groovy

I have a Groovy class and want to make sure that certain attributes are always set in the constructor.
Is there any way to way to make attributes mandatory in a Groovy class?
Thanks

You could use #TupleConstructor with specific attribute force :
import groovy.transform.TupleConstructor
#TupleConstructor(force=true)
class Car {
String brand
List options
private boolean sold = false
// constructor
Car(boolean sold) {
this.sold = sold
}
boolean hasBeenSold() { sold }
}
}
car = new Car(true)
assert car.hasBeenSold
More info

Related

How to change value of java superclass read only field in groovy?

I got class:
public abstract class AbstractEntity {
#Getter
#Column(nullable = false, unique = true, updatable = false)
private UUID uuid = UUID.randomUUID();
}
and test:
def 'should be transitive: if x.equals(y) and y.equals(z) then x.equals(z)'() {
given:
AbstractEntity place = new Place()
AbstractEntity secondPlace = new Place()
AbstractEntity thirdPlace = new Place()
and: 'all entities has same uuid what makes them equal'
secondPlace.changeUuid(place.uuid)
thirdPlace.changeUuid(place.uuid)
line secondPlace.changeUuid(place.uuid) throws exception: groovy.lang.ReadOnlyPropertyException: Cannot set readonly property
How can I set this field value without using java reflection?
You seem to have an attribute in the #Column 'updatable = false. My first reaction is to think that this stops variables from being updated.
There is also no #Setter annotation which could be useful in this scenario.
Then you could use this method within your test.

Extending PX.Objects.CR.CRMSourcesAttribute

I am trying to add entries to the CRMSourcesAttribute class for more options in the Opportunities Dropdown Box.
I see PXAttributeExtension but apparently this is not meant for developers as I cannot provide a constructor for the base class PXStringListAttribute where the actual values are set.
There must be a simple way to add entries to that dropdown box!
You don't even need to do any customization or programming to change this list. By adding the screen to Automation Steps screen, you can put the Source field in the Fields tab of the automation definition and override the combo box values. Please note that if you're trying that with Acumatica 5.0, you may need to remove the "Opportunities" list as entry point from the generic inquiries, otherwise it will interfere with your selection when you try to select the Opportunities screen from the Automation Steps.
If you want to do it via programming - you'd need to replace the CRMSourcesAttribute on the field with your own version of this attribute. This attribute is fairly simple and is only derived from PXStringList attribute:
public class CRMSourcesAttribute : PXStringListAttribute
{
public const string _WEB = "W";
public const string _PHONE_INQ = "H";
public const string _REFERRAL = "R";
public const string _PURCHASED_LIST = "L";
public const string _OTHER = "O";
public CRMSourcesAttribute() :
base(new[] { _WEB, _PHONE_INQ, _REFERRAL, _PURCHASED_LIST, _OTHER },
new[] { Messages.Web, Messages.PhoneInq, Messages.Referral, Messages.PurchasedList, Messages.Other })
{
}
}

initializing derived class member variables using base class reference object

I came across a lot of code in our company codebase with the following structure
class Base
{
public Base (var a, var b)
{
base_a = a;
base_b = b;
}
var base_a;
var base_b;
}
class Derived:Base
{
publc Derived (var a,b,c,d): base (a,d)
{
der_c = c;
der_d = d;
}
var der_c;
var der_d;
var der_e;
}
class Ref
{
Base _ref;
public Ref( var a,b,c,d)
{
_ref = new Derived (a,b,c,d)
}
public void method( )
{
_ref.der_e = 444; // won't compile
}
}
What is the correct way to initialize der_e ? What is the advantages of having a reference of base class and using an object derived class for _ref ? Just the fact that using a base class reference can hold multiple derived class objects ? If that's the case, should all the member variables of derived class be initialized during construction itself (like this: _ref = new Derived (a,b,c,d) ). What if I want to initialize _ref.der_e later in a method ? I know I can do this (var cast_ref = _ref as Derived; cast_ref.der_e = 444) but this look doesn't seem to the best practice. What is the idea of having such a structure and what is the correct of initializing a member of a derived class object after it has been constructed ?
Those are too many questions in a single post.
What is the correct way to initialize der_e ?
For initializing der_e you will have to have Reference of Derived class as it knows about the der_e property and not Base class.
What is the advantages of having a reference of base class and using
an object derived class for _ref ?
Yes that's called Polymorphism which is the essence of Object Oriented Programming. It allows us to hold various concrete implementations without knowing about the actual implementation.
If that's the case, should all the member variables of derived class
be initialized during construction itself (like this: _ref = new
Derived (a,b,c,d) )
There is no such rule. It depends on your scenario. If the values are not meant to be changed after the creation of the object and the values are known before hand during construction of the object then they should be initialized during construction.
Again if there are various scenarios like sometimes values are known and sometimes not then there can be Overloaded Constructors, which take different arguments.
What if I want to initialize _ref.der_e later in a method ?
That is perfectly fine, it depends on what you are trying to achieve. The question is not a concrete one but an abstract one in which it is difficult to comment on what you are trying to achieve.
I know I can do this (var cast_ref = _ref as Derived; cast_ref.der_e =
444) but this look doesn't seem to the best practice.
I am sharing some Java code which is similar to C# as I am from Java background
//This class knows about Base and nothing about the Derived class
class UserOfBase{
Base ref;
//Constructor of UserOfBase gets passed an instance of Base
public UserOfBase(Base bInstance){
this.ref = bInstance;
}
//Now this class should not cast it into Derived class as that would not be a polymorphic behavior. In that case you have got your design wrong.
public void someMethod(){
Derived derivedRef = (Derived)ref; //This should not happen here
}
}
I am sharing some references which would help you with this, as I think the answer can be very long to explain.
Factory Pattern
Dependency Injection
Head First Design Patterns
Posts on SO regarding polymorphism
You can create a constructor in your derived class and map the objects or create an extension method like this:
public static class Extensions
{
public static void FillPropertiesFromBaseClass<T1, T2>(this T2 drivedClass, T1 baseClass) where T2 : T1
{
//Get the list of properties available in base class
System.Reflection.PropertyInfo[] properties = typeof(T1).GetProperties();
properties.ToList().ForEach(property =>
{
//Check whether that property is present in derived class
System.Reflection.PropertyInfo isPresent = drivedClass.GetType().GetProperty(property.Name);
if (isPresent != null && property.CanWrite)
{
//If present get the value and map it
object value = baseClass.GetType().GetProperty(property.Name).GetValue(baseClass, null);
drivedClass.GetType().GetProperty(property.Name).SetValue(drivedClass, value, null);
}
});
}
}
for example when you have to class like this:
public class Fruit {
public float Sugar { get; set; }
public int Size { get; set; }
}
public class Apple : Fruit {
public int NumberOfWorms { get; set; }
}
you can initialize derived class by this code:
//constructor
public Apple(Fruit fruit)
{
this.FillPropertiesFromBaseClass(fruit);
}

How to dynamically create collections of derived objects?

This question may appear to have been answered before but I have been unable to find exactly what I need. Here is my situation:
// Base class
interface IAnimal {};
public abstract class Animal : IAnimal{}
// Derived classes
interface IDog {}
public class Dog : Animal, IDog { }
interface ICat { }
public class Cat : Animal, ICat { }
interface ITiger { }
public class Tiger : Animal, ITiger { }
interface ILion { }
public class Lion : Animal, ILion { }
// Collection Classes
interface IPets { }
public class Pets
{
IDog dog = new Dog();
ICat cat = new Cat();
}
interface ICircus { }
public class Circus
{
ITiger tiger = new Tiger();
ILion lion = new Lion();
}
I would like to create the collections at run time in an generic Event class by reading in a list animals from xml that would make up the collection. What would be the correct way to accomplish this?
Thanks in advance.
This is kind of an answer to my own question. Maybe this will help others.
I chose a very generic example to illustrate my situation because I have uses for this in many places in Windows Forms, XNA and Silverlight that are all very different.
When I used the Activator, I found out that it assumes the executing assembly. My method is in a library so I had to load a different assembly. Next I had to make sure that I had the right namespace. My base class is in a library and the derived classes are in another namespace so this will require refactoring to properly create the list.
Another problem I found was that the Activator assumes a constructor with no parameters. In my test case all my derived classes are XNA game components with a parameter of type Game.
Have to do some refactoring to test out the interfaces and how the game objects are to interact.
Will be back to this list when I have something further.
Does this sort of example help? (It's from some of my code I happened to have handy.) The key point here is the use of reflection in Activator.CreateInstance(...).
public static List<dynamic> LoadChildEntities(XElement entityElt)
{
var children = new List<dynamic>();
foreach(XElement childElt in entityElt.Elements("entity"))
{
// Look up the C# type of the child entity.
string childTypename = "MyNamespace." + Convert.ToString(childElt.Attribute("type").Value);
Type childType = Type.GetType(childTypename);
if(childType != null)
{
// Construct the child entity and add it to the list.
children.Add(Activator.CreateInstance(childType, childElt));
}
else
{
throw new InvalidOperationException("No such class: " + childTypename);
}
}
return children;
}
If you want a list of IAnimal instead, it wouldn't be too tricky to change.

AllowMultiple does not work with Property Attributes?

I'm tying to collect all Custom Attributes placed over a Property. There are more than one Attributes of the same type assigned to the Property, but when collecting them , the resulting collection only contains the first Attribute of the specific type:
The Attribute class
[AttributeUsage(System.AttributeTargets.Property,
AllowMultiple = true)]
public class ConditionAttribute : Attribute{...}
Usage:
[ConditionAttribute("Test1")]
[ConditionAttribute("Test2")]
[ConditionAttribute("Test3")]
public Color BackColor{get; set;}
Now when looping through all Props of the object 'value' whose class contains the Prop "BackColor":
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value))
{
foreach (Attribute attribute in property.Attributes)
{ ... }
....
}
the collection property.Attributes only contains ONE Attribute of type "ConditionAttribute" : The one with "Test1". The others are ignored;-(
So does AllowMultiple not work for Property Attributes ?
Thanks in advance
henrik
According to a post on MSDN, this is by design as part of the PropertyDescriptor class.
However, you can actually solve the problem by overriding TypeId in your custom attribute (Thanks to Ivan from Mindscape for pointing this out):
public override object TypeId
{
get
{
return this;
}
}
Yes, it does work. Not sure why it does not work via PropertyDescriptors.
You can always do: Attribute.GetCustomAttributes(methodInfo, typeof(ConditionAttribute))
Another way to tweak this,
[ConditionAttribute("Test1,Test2,Test3")]
public Color BackColor{get; set;}
and in your validation code,
Dim lstProperties() As String = _ChkColors.Split(",")
For each strProp as string in lstPropertyes
' your validation
' return
Next

Resources