Given this Groovy domain class (for persistence in MongoDB):
#Canonical
class Counter {
#Id String id
String name
long count = 0
Date createdTimestamp = new Date()
Date updatedTimestamp = new Date()
}
Since only 'name' need be supplied when creating a new Counter, is there a way to call the #Canonical-generated map-based constructors, as the Groovy approach below will not compile in Java:
// Invalid Java code
counterRepository.save(new Counter(name: newCounterName));
Must I either use the implicit setter:
// Valid, but a bit verbose, Java code
Counter counter = new Counter();
counter.setName(newCounterName);
counterRepository.save(counter);
Or create a static factory method in the Counter POGO:
static Counter init(String newCounterName) {
return new Counter(name: newCounterName)
}
Enabling the following:
// Valid, concise, but perhaps/hopefully redundant?
counterRepository.save(Counter.init(counterName));
The last approach is the one currently used.
If I understand you correctly you don't really want to use #Cannonical, you are more after #TupleConstructor. With this AST you can specify fields you want to use and have more fine grained controller over the constructor. An example could be:
#TupleConstructor(includes=['name'])
class Counter {
#Id String id
String name
long count = 0
Date createdTimestamp = new Date()
Date updatedTimestamp = new Date()
}
For more see http://docs.groovy-lang.org/latest/html/gapi/groovy/transform/TupleConstructor.html
Related
I am wondering how the drools accumulate element work inside Optaplanner? It seems that the sum() function is not returning the value I expect. I have two simple POJOs ProductionPackage and SKU.
#PlanningEntity
public class ProductionPackage{
// This is a custom date object containing information about a date. Constant Date initialized on start.
// Custom date object NOT util.Date or sql.Date
private Date date;
// The number of units in this package. Constant value initialized on program start.
private int productionUnits;
// The ID of the production package
private int productionPackageId;
// The SKU assigned to this production package
#PlanningVariable(valueRangeProviderRefs = "skuRange")
private SKU sku;
// Getters, setters, constructors...
}
public class SKU {
// Unique identifier for this product.
private String sku;
//Getters, setters, constructors...
}
The PlanningSolution looks as follows:
#PlanningSolution
public class ProductionPlan {
#ProblemFactCollectionProperty
#ValueRangeProvider(id = "skuRange")
private List<SKU> skuList;
#ProblemFactCollectionProperty
private List<Date> dateList;
#PlanningEntityCollectionProperty
List<ProductionPackage> ProductionPackageList;
//Getters, setters, constructors...
}
Basically I have many ProductionPackages and I am trying to assign one SKU to each production package. The productionUnits field of the 'ProductionPackage' specifies how much of the assigned SKU has to be produced. For simplicity, lets say that the productionUnits of all productionPackages is 1(could be any integer > 0).
One constraint of this problem is that there should be at least 10 units produced per SKU per Date. I am trying to implement this constraint using Drools as follows:
rule "At least 10 production units per SKU and per Day"
enabled true
when
// Bind SKU to variable
$sku : SKU()
// Bind Date object to variable
$date : Date()
accumulate(
ProductionPackage(sku == $sku,
date == $date,
$productionUnits : productionUnits);
$productionUnitsTotal : sum($productionUnits);
$productionUnitsTotal < 10
)
then
// For debugging purposes
System.out.println("SKU: " + $sku.toString());
System.out.println("Date: " + $date.toString());
System.out.println("ProductionUnits: " + $productionUnitsTotal);
scoreHolder.addHardConstraintMatch(kcontext, -1);
end
In the Drools documentation it is stated that the accumulate element iterates over all the elements of a collection. To me, this rule selects a combination of SKU and Date. It then iterates over the ProductionPackageList containing ProductionPackage objects. If the Date and SKU match with the previously selected SKU and Date objects it sums the productionUnits. I expect this to return the total units produced per SKU and per Date (and it looks like it does sometimes). However, I am noticing that the System.out.println("ProductionUnits: " + $productionUnitsTotal); statement is printing 0. This is really odd to me since productionUnits is always an integer > 0. How can it print 0? If both conditions match($date = date and $sku == sku), an SKU should never have 0 production units because it is already assigned to a production package whose productionUnits > 0.
I think the error stems from the fact that I really don't understand what Optaplanner or Drools are doing. I have turned on DEBUG/TRACE mode however those haven't helped me much.
I've a use case where I need to bind configuration properties based on two prefixes, one of which is determined at runtime. Let's say the constant prefix is foo and the runtime prefix is bar.
Given a new instance of Java Bean class FooBar, the code should bind all environment variables FOO_, then overwrite with all environment variables BAR_.
There's a way to dynamically bind a prefix to a class, as I had stated in this ticket (sample code shown below). However, what's missing is the merging of the results.
var bindable = Bindable.of(FooBar.class);
var properties = ConfigurationPropertySources.get(env);
new Binder(properties)
.bind("prefix", bindable)
.orElse(new FooBar());
Example:
public class FooBar {
private Duration latency = Duration.ofMillis(500L);
// other properties
// getters, setters
}
If there are no environment variables FOO_LATENCY or BAR_LATENCY, FooBar.getLatency() is 500 ms. If only one of FOO_LATENCY and BAR_LATENCY is present, FooBar.getLatency() takes its value. If both FOO_LATENCY and BAR_LATENCY are present, FooBar.getLatency() takes the value of BAR_LATENCY.
Any idea how can this be done?
UPDATED
Just call bind again. It only assigns values that are found in the configuration properties, and last prefix bound will win, on a property-by-property basis.
Example
class FooBar {
private String a;
private String b = "B";
private String c;
private String d;
private String e = "E";
// Getter, setters, and toString here
}
Properties (YAML)
x.a: Hello
x.b: World
z.a: Goodbye
z.c: Test
Test
Binder binder = Binder.get(env);
FooBar fooBar = new FooBar();
System.out.println(fooBar);
fooBar = binder.bind("x", Bindable.ofInstance(fooBar)).orElse(fooBar);
System.out.println(fooBar);
fooBar = binder.bind("y", Bindable.ofInstance(fooBar)).orElse(fooBar);
System.out.println(fooBar);
fooBar = binder.bind("z", Bindable.ofInstance(fooBar)).orElse(fooBar);
System.out.println(fooBar);
Output
FooBar[a=null, b=B, c=null, d=null, e=E]
FooBar[a=Hello, b=World, c=null, d=null, e=E]
FooBar[a=Hello, b=World, c=null, d=null, e=E]
FooBar[a=Goodbye, b=World, c=Test, d=null, e=E]
As you can see, the third binding overrides the values from the first, but only for properties that are actually configured, which is why the second binding does nothing.
I also simplified the logic to skip the use of ConfigurationPropertySources.get().
I have to save the old data to a history table whenever a field is changed in the current table. Hence, I have to create a history Domain class with same fields as original Domain class. For now, I am manually creating the history Domain class and saving the older data into it whenever the values are updated in the original table.
Is there a way to auto generate a history Domain class with same fields whenever a new Domain class is created.
Main Domain class is:
class Unit {
String name
String description
Short bedrooms = 1
Short bathrooms = 1
Short kitchens = 1
Short balconies = 0
Short floor = 1
Double area = 0.0D
Date expDate
Date lastUpdated
static hasMany = [tenants:Tenant]
static belongsTo = [property: Property]
}
History Domain class should be like this:
class UnitHistory {
String name
String description
Short bedrooms = 1
Short bathrooms = 1
Short kitchens = 1
Short balconies = 0
Short floor = 1
Double area = 0.0D
Date expDate
Date lastUpdated
static hasMany = [tenants:Tenant]
static belongsTo = [property: Property]
}
Maybe you could add beforeInsert and beforeUpdate methods to your Unit domain as follows:
class Unit {
String name
String description
Short bedrooms = 1
Short bathrooms = 1
Short kitchens = 1
Short balconies = 0
Short floor = 1
Double area = 0.0D
Date expDate
Date lastUpdated
def beforeInsert() {
addHistory()
}
def beforeUpdate() {
addHistory()
}
def addHistory(){
new UnitHistory( this.properties ).save( failOnError: true )
}
}
I would need to know more about the actual requirements to know for sure what the best thing to do is but one likely solution to consider would be to use an event listener that would create instances of the history class each time an instance of the main class is inserted and/or updated. At https://github.com/jeffbrown/gorm-events-demo/blob/261f25652e5fead8563ed83f7903e52dfb37fb40/src/main/groovy/gorm/events/demo/listener/AuditListener.groovy#L22 is an example of an event listener. Instead of updating the instance like you see in that example, you could create a new instance of your history class, copy the relevant stuff and then persist that newly created history instance.
See https://async.grails.org/latest/guide/index.html#gormEvents for more info about GORM events.
I hope that helps.
Intro
I am using Apache Storm (Local mode, not Remote mode) in my Java project and when creating the topology I need to pass an object to one of the bolts
TopologyBuilder builder = new TopologyBuilder();
.....
builder.setBolt("last-bolt", new MyBolt(Classifier.SECONDS)).someGrouping(...);
.....
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("test", conf, builder.createTopology());
The object itself has some non-serializable fields. Instead of subclassing the classes to which those fields belong and making them Serializable I have taken another approach. Since the actual object isn't gonna be changing a lot and it can be enumerated I've decided to make it an enum and pass it like that to bolt's tasks. The good thing about enum is that it is serializable under all costs. This approach works in local mode because (if I understood Storm correctly) there is only one JVM running on my computer and things can't get complicated actually.
Question
If the enum consists of a static final non-serializable field will that field be constructed properly when the enum is deserialized by another process on a different machine or a cluster running multiple JVMs?
The actual enum (static final field is at the end)
public enum Classifier {
SECONDS {
public String classify(String timestamp) {
DateTime dateTime = formatter.parseDateTime(timestamp);
int second = dateTime.getSecondOfMinute();
if (second <= 30) {
return "00 - 30";
} else {
return "30 - 60";
}
}
public int getNumberOfCategories() {
return 2;
}
},
WEEK {
public String classify(String timestamp) {
DateTime dateTime = formatter.parseDateTime(timestamp);
int dayOfWeek = dateTime.getDayOfWeek();
String typeOfDay = (dayOfWeek >= 1 && dayOfWeek <= 5) ? "workday" : "weekend";
int hour = dateTime.getHourOfDay();
String hourInterval = hour + " - " + (hour == 23 ? 0 : hour + 1);
return typeOfDay + " " + hourInterval;
}
public int getNumberOfCategories() {
return 48;
}
};
private static final DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
public abstract String classify(String timestamp);
public abstract int getNumberOfCategories();
}
More details
DateTimeFormatter and DateTime are from org.joda.time package.
All static final fields are initialized when class is loaded. Whatever serialization mechanism is used it will first initialize the static fields and execute static initialization blocks. Note that static fields are not deserialised because we are not deserialising classes but objects (please also refer to this answer https://stackoverflow.com/a/6429497/1937263).
So the answer is yes, the field should be constructed properly.
I am studying data object in Java
I have question for creating the data object dynamically.
For example ,
we have...
public class tasks {
private int vmnumber;
private int tasknumber;
private String status;
public tasks(int vmnumber , int tasknumber , String status) {
this.vmnumber = vmnumber;
this.tasknumber = tasknumber;
this.status = status; }
and there are some getvmnumber gettasknumber , getstatus , and some set functions for
what I understand about creating data object is we have to initialize each time.
for example , in the main file ,
public class task{
public static void main(String [] args){
task t = null , t2 = null;
t = new task();
t.tasknumber = 3;
t.vmnumber = 4;
t.status = "Start";
t2 = new task();
t.tasknumber = 2;
t.vmnumber = 1;
t.status = "Wait";
}
however, i would like to how we can create data object dynamically because program possibly get the information of tasks on real time.(then we can't manually create the data object, we need to something which can create the data object dynamically...)
Second, I would like to know how to get the data from data object.
For example , if we want to find all the information of task number 3 , what should i do ?
lets say , we have task1, task2, task3 data object and we want to see the all information of task1. then what should i do ?
thanks
There are few points to discuss, from your question.
I guess you want to create new tasks, which is maybe a request from the user interace of your application, or a webservice, a batch...
Well, you already know how to create object : with the new keyword. Depending on the original request, your main function may have to create multiple instances of the same class, "Task".
More, when you instantiate the class "Task", you would never want to assign directly values to the properties of it.
So, instead of coding t.tasknumber = 3, you should code : t.setTaskNumber(3)
Also, you should rename the properties of your class to reflect the JavaBeans conventions :
- private int taskNumber instead of tasknumber
Of course, it is only a convention, and it is not mandatory in your program. But it helps generating getters/setters, and, well, it is a convention :-)
To retrieve "information" within your created tasks, you only have to call the getters :
- myTask.getTaskNumber()
Hope this helps you a little bit.