I need help writing a Drools rule. I have two classes named Context and CreditReport.
Context is inserted as a fact into the knowledge session before the rules are fired.
I need to write a rule that prints 'Excellent' on the console when the Credit Score is more than 800.
Ideally, I'd insert CreditReport directly into the session, but unfortunately I do not have that option.
The rule that I've written doesn't look good as:
The then part has an if statement
I am type-casting Object to CreditReport
Thanks for your help!
// Context.java
public class Context {
private Map<String, Object> data = Maps.newHashMap();
public <T> T getData(final String key, final Class<T> clazz) {
return clazz.cast(data.get(key));
}
public void putData(final String key, final Object value) {
this.data.put(key, value);
}
}
// CreditReport.java
public class CreditReport {
private final String name;
private final int creditScore;
public String getName() {
return this.name;
}
public int getCreditScore() {
return this.creditScore;
}
}
// Main method
context.put("creditReport", new CreditReport("John", 810));
session.insert(Arrays.asList(context));
session.fireAllRules();
// Rule
rule "Excellent_Score"
when Context($creditReportObject : getData("creditReport"))
then
final CreditReport creditReport = (CreditReport) $creditReportObject;
if (creditReport.getCreditScore() >= 800) {
System.out.println("Excellent");
}
end
What makes you insert a List<Context> containing a single Context object? The Java code should do
context.put("creditReport", new CreditReport("John", 810));
session.insert( context );
session.fireAllRules();
The rule can now be written as
rule "Excellent_Score"
when
Context( $creditReportObject : getData("creditReport") )
CreditReport( creditScore > 800 ) from $creditReportObject
then
System.out.println("Excellent");
end
You could, of course, get and insert the CreditReport from Context. - I suspect it's more convoluted that what you've shown, but "I do not have that option" is a code smell anyway.
Edit A single rule for more than one reason for printing "excellent" could be written like the one below, although this isn't much better that two rules, considering that you can wrap the RHS into a method or DRL function.
rule "Excellent_Score_2"
when
Context( $creditReport : getData("creditReport"),
$account: getData("account") )
( CreditReport( creditScore > 800 ) from $creditReport
or
Account( balance >= 5000 ) from $account )
then
System.out.println("Excellent");
end
Related
I have a complex enum class in my spring boot application which holds different status values for different systems.
package com.foo;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public enum Status {
FOO_STATUS("Status1" ,"status_1", "STATUS_1", "stat1"),
BAR_STATUS("Status2" ,"status_2", "STATUS_2", "stat2" ),
FOO1_STATUS("Status3" ,"status_3", "STATUS_3", "stat3" ),
BAR1_STATUS("Status4" ,"status_4", "STATUS_4", "stat4" ),
....
....
....
private final String system1Status;
private final String system2Status;
private final String system3Status;
private final String system4Status;
private static Map<String, String> statusMap;
Status(String system1Status, String system2Status, String system3Status, String system4Status) {
this.system1Status = system1Status;
this.system2Status = system2Status;
this.system3Status = system3Status;
this.system4Status = system4Status;
}
public String getSystem1Status() {
return system1Status;
}
public String getSystem2Status() {
return system2Status;
}
public String getSystem3Status() {
return system3Status;
}
public String getSystem4Status() {
return system4Status;
}
private static void initializeMapping() {
statusMap = new HashMap<>();
for (Status map : Status.values()) {
statusMap.put(map.getSystem1Status(), map.getSystem2Status());
}
}
public static String getSystem2StatusForSytem1Status(String status) {
if (statusMap == null) {
initializeMapping();
}
if (statusMap.containsKey(status)) {
return statusMap.get(status);
}
return null;
}
public static String getSystem3StatusForSytem1Status(String status) {
....
}
public static String getSystem4StatusForSytem2Status(String status) {
....
}
public static String getSystem3StatusForSytem2Status(String status) {
....
}
....
....
}
The enum holds status string mapping for various systems. It also has methods to get different system status by supplying the current system status.
Ex: We can get System1 status by sending the System 2 status value.
As the enum is getting more complex , is there any alternate way to hold this static data?
PS: I know this can be moved to a reference table in DB, But I am looking for any alternate within the code (like loading from yaml file).
The concern about the enum getting more and more complex is only valid if that complexity is accidental, not inherent. Otherwise, switching to a different approach would just move that complexity elsewhere (which kind of seems to be the case in your example). I think it makes sense to keep the enum (even if it grows complex) iif the following conditions are met:
There is no reasonable scenario in which you would want/need to account for new statuses or new mappings (or drop existing ones) without changing the code.
You rely on at least some enum features available out of the box, so you would have to reimplement those by hand. E.g. values() listed in a determinate order, valueOf() used with canonical String labels, ordinal() to infer position, compareTo(), name(), serialization, etc.
You use the enum constants polymorphically (and maybe you need to alter the behavior for some of them without a full-fledged class hierarchy) or you want to leverage the compiler check for exhaustive case branches in switch expressions (with newer java versions).
I'm trying to refactor my code, because methods I created are very similar. Even intelliJ emphasises it. Aim of methods is to map (using switch statements) type 'MessageType' to also 'MessageType', which is from different package. The problem is that input types for switch statement are also from different packages.
private MessageType convertToInsurancePolisyMessageType1 (pl.different.MessageType messageType) {
switch (messageType) {
case WARN: return MessageType.WARN;
case INFO: return MessageType.INFO;
case ERROR: return MessageType.ERROR;
default: throw new IllegalArgumentException(messageType.name());
}
}
private MessageType convertToInsurancePolisyMessageType2 (com.other.MessageType messageType) {
switch (messageType) {
case WARNING: return MessageType.WARN;
case INFO: return MessageType.INFO;
case ERROR: return MessageType.ERROR;
default: throw new IllegalArgumentException(messageType.name());
}
}
Is there any easy way to refactor this? Or should I leave like this?
Well, after all I don't see nothing bad with your switch approach:)
Just to throw some alternative you can use maps:
public class MessageTypeConverter {
private static final Map<pl.different.MessageType, com.other.MessageType> DIRECT_MAPPING =
new EnumMap<pl.different.MessageType, com.other.MessageType>(pl.different.MessageType.class) {{
put(pl.different.MessageType.WARN, com.other.MessageType.WARN);
put(pl.different.MessageType.INFO, com.other.MessageType.INFO);
put(pl.different.MessageType.ERROR, com.other.MessageType.ERROR);
}};
private static final Map<com.other.MessageType, pl.different.MessageType> REVERSE_MAPPING =
new EnumMap<com.other.MessageType, pl.different.MessageType>(com.other.MessageType.class) {{
put(com.other.MessageType.WARN, pl.different.MessageType.WARN);
put(com.other.MessageType.INFO, pl.different.MessageType.INFO);
put(com.other.MessageType.ERROR, pl.different.MessageType.ERROR);
}};
private com.other.MessageType convertToInsurancePolisyMessageType1(pl.different.MessageType messageType) {
return DIRECT_MAPPING.computeIfAbsent(messageType, key -> throw new IllegalArgumentException(messageType.name()));
}
private pl.different.MessageType convertToInsurancePolisyMessageType2(com.other.MessageType messageType) {
return REVERSE_MAPPING.computeIfAbsent(messageType, key -> throw new IllegalArgumentException(messageType.name()));
}
}
I'm afraid that there is no work around to have some sort of listing/mapping between values of each of the input MessageType and the returned one.
Perhaps you could try to do some reflection based approach considering that names are very similar... however I think that would bring nothing but problems down the road if such names change and it has a performance hit if you are doing this transformation often.
To complement other answers based on static maps, which are quite fine btw, if you have control on the code return MessageType enum (i.e. you are developing such enum) I think that you should consider to encapsulate the conversion within that enum by overloading the same name for each type of argument.
There are several option here... I personally prefer of for the name. valueOf is acceptable but since valueOf(String) would throw an NoSuchElementException you should keep that behavior. Let's stick to of here:
enum MessageType {
WARN, INFO, ERROR;
private static Map<pl.different.MessageType, MessageType> byPlDiffMType =
new EnumMap<>(Map.of(
pl.different.MessageType.WARN, WARN,
pl.different.MessageType.INFO, INFO,
pl.different.MessageType.ERROR, ERROR
));
private static Map<com.other.MessageType, MessageType> byCOthMType =
new EnumMap<>(Map.of(
com.other.MessageType.WARNING, WARN,
com.other.MessageType.INFO, INFO,
com.other.MessageType.ERROR, ERROR
));
public static MessageType of(pl.different.MessageType value) {
return of(byPlDiffMType, value);
}
public static MessageType of(com.other.MessageType value) {
return of(byCOthMType, value);
}
private static <V> MessageType of(Map<V, MessageType> map, V value) {
final MessageType result = map.get(value);
if (result == null) {
throw new IllegalArgumentException();
} else {
return result;
}
}
}
Even if you dont have control on that class source you probably better of performance wise using EnumMap rather than regular Maps (e.g. HashMap).
I know that you are not saving much code though ... but I think that conversion into a enum make sense to be encapsulated in the enum class itself if you are developing it.
The only way to reduce line is to do some kind of matching thru the common names adding ifs for those that are different but I would not encourage to do that as it would break silently with changes down the road and is probrably less "performy".
Something like this (with credit to RealSkeptic - sorry your comment appeared after I started writing this, but the same thing!):
public class DifferentMessageTypeConverter {
public enum DifferentMessageType {
WARNING, INFO, ERROR;
}
public enum InsurancePolicyMessageType {
WARN, INFO, ERROR;
}
private static final Map<DifferentMessageType, InsurancePolicyMessageType> DIFF_TO_INS_MAPPING;
static {
DIFF_TO_INS_MAPPING = new HashMap<>();
DIFF_TO_INS_MAPPING.put(DifferentMessageType.WARNING, InsurancePolicyMessageType.WARN);
DIFF_TO_INS_MAPPING.put(DifferentMessageType.INFO, InsurancePolicyMessageType.INFO);
DIFF_TO_INS_MAPPING.put(DifferentMessageType.ERROR, InsurancePolicyMessageType.ERROR);
}
public InsurancePolicyMessageType convertToInsurancePolisyMessageType1(DifferentMessageType dmt) {
dmt = Optional.ofNullable(dmt)
.orElseThrow(() -> new IllegalArgumentException("dmt must not be null"));
return Optional.ofNullable(dmt)
.map(DIFF_TO_INS_MAPPING::get)
.orElseThrow(() -> new IllegalArgumentException(messageType.name()));
}
}
I have a below class in which isValid method is being called.
I am trying to extract few things from Record object in the isValid method. And then I am validating few of those fields. If they are valid, then I am populating the holder map with some additional fields and then I am populating my DataHolder builder class and finally return the DataHolder class back.
If they are not valid, I am returning null.
Below is my class:
public class ProcessValidate extends Validate {
private static final Logger logger = Logger.getInstance(ProcessValidate.class);
#Override
public DataHolder isValid(String processName, Record record) {
Map<String, String> holder = (Map<String, String>) DataUtils.extract(record, "holder");
String deviceId = (String) DataUtils.extract(record, "deviceId");
Integer payId = (Integer) DataUtils.extract(record, "payId");
Long oldTimestamp = (Long) DataUtils.extract(record, "oldTimestamp");
Long newTimestamp = (Long) DataUtils.extract(record, "newTimestamp");
String clientId = (String) DataUtils.extract(record, "clientId");
if (isValidClientIdDeviceId(processName, deviceId, clientId) && isValidPayId(processName, payId)
&& isValidHolder(processName, holder)) {
holder.put("isClientId", (clientId == null) ? "false" : "true");
holder.put("isDeviceId", (clientId == null) ? "true" : "false");
holder.put("abc", (clientId == null) ? deviceId : clientId);
holder.put("timestamp", String.valueOf(oldTimestamp));
DataHolder dataHolder =
new DataHolder.Builder(record).setClientId(clientId).setDeviceId(deviceId)
.setPayId(String.valueOf(payId)).setHolder(holder).setOldTimestamp(oldTimestamp)
.setNewTimestamp(newTimestamp).build();
return dataHolder;
} else {
return null;
}
}
private boolean isValidHolder(String processName, Map<String, String> holder) {
if (MapUtils.isEmpty(holder)) {
// send metrics using processName
logger.logError("invalid holder is coming.");
return false;
}
return true;
}
private boolean isValidpayId(String processName, Integer payId) {
if (payId == null) {
// send metrics using processName
logger.logError("invalid payId is coming.");
return false;
}
return true;
}
private boolean isValidClientIdDeviceId(String processName, String deviceId, String clientId) {
if (Strings.isNullOrEmpty(clientId) && Strings.isNullOrEmpty(deviceId)) {
// send metrics using processName
logger.logError("invalid clientId and deviceId is coming.");
return false;
}
return true;
}
}
Is my isValid method doing lot of things? Can it be broken down in multiple parts? Or is there any better way to write that code?
Also I don't feel great with the code I have in my else block where I return null if record is not valid. I am pretty sure it can written in much better way.
Update:
In my case this is what I was doing. I am calling it like this:
Optional<DataHolder> validatedDataHolder = processValidate.isValid(processName, record);
if (!validatedDataHolder.isPresent()) {
// log error message
}
// otherwise use DataHolder here
So now it means I have to do like this:
boolean validatedDataHolder = processValidate.isValid(processName, record);
if (!validatedDataHolder) {
// log error message
}
// now get DataHolder like this?
Optional<DataHolder> validatedDataHolder = processValidate.getDataHolder(processName, record);
You are correct isValid() is doing too many things. But not only that, when most of us see a method that is called isValid() - we expect a boolean value to be returned. In this case, we're getting back and instance of DataHolder which is counterintuitive.
Try to split the things that you do in the method, for example:
public static boolean isValid(String processName, Record record) {
return isValidClientIdDeviceId(processName, record) &&
isValidPayId(processName, record) &&
isValidHolder(processName, record);
}
and then construct DataHolder in a different method, say:
public static Optional<DataHolder> getDataHolder(String processName, Record record) {
Optional<DataHolder> dataHolder = Optional.empty();
if (isValid(processName, record)) {
dataHolder = Optional.of(buildDataHolder(processName, record));
// ...
}
return dataHolder;
}
It will make your program easier to both read and maintain!
I think things start with naming here.
As alfasin is correctly pointing out, the informal convention is that a method named isValid() should return a boolean value. If you really consider returning a DataHolder; my suggestion would be to change name (and semantics a bit), like this:
DataHolder fetchHolderWithChecks(String processName, Record ...)
And I wouldn't return null - either an Optional; or simply throw an exception. You see, don't you want to tell your user about that error that occured? So when throwing an exception, you would have a mean to provide error messages to higher levels.
On validation itself: I often use something like this:
interface OneAspectValidator {
void check(... // if you want to throw an exception
boolean isValid(... // if you want valid/invalid response
And then various implementations of that interface.
And then, the "validation entry point" would somehow create a list, like
private final static List<OneAspectValidator> validators = ...
to finally iterate that list to validate those aspects one by one.
The nice thing about that approach: you have the code for one kind of validation within one dedicated class; and you can easily enhance your validation; just by creating a new impl class; and adding a corresponding object to that existing list.
I know this might not be directly actionable, but the first thing you should do if you want to clean up this code is to use OO (Object-Orientation). If you are not using OO properly, then there is no point arguing the finer details of OO, like SRP.
What I mean is, I couldn't tell what you code is about. Your classnames are "ProcessValidate" (is that even a thing?), "Record", "DataHolder". That is pretty suspect right there.
The string literals reveal more about the domain ("payId", "deviceId", "clientId") than your identifiers, which is not a good sign.
Your code is all about getting data out of other "objects" instead of asking them to do stuff (the hallmark of OO).
Summary: Try to refactor the code into objects that reflect your domain. Make these objects perform tasks specific to their responsibilities. Try to avoid getting information out of objects. Try to avoid setting information into objects. When that is done, it will be much more clear what SRP is about.
I need to create a structure that need to represent the following (For Category and Sub-Category).Its just one level deep. I am thinking of doing it using Java Enums and not sure how to represent this hierarchical structure.
My java objects (business objects) that represent a device will have both category and sub-category properties and I want to use an Enum instead of using integer codes like 100, 1 etc.. Some devices will have only category but not the sub-category (like 300 in the following example).
100 Switch
1 Interior
2 Exterior
200 Security Sensor
1 Door Sensor
2 Leak Sensor
3 Motion Sensor
300 Camera
Any help is appreciated.
Thanks
This java.dzone article showcases is a beautiful example of hierarchical enums:
public enum OsType {
OS(null),
Windows(OS),
WindowsNT(Windows),
WindowsNTWorkstation(WindowsNT),
WindowsNTServer(WindowsNT),
Windows2000(Windows),
Windows2000Server(Windows2000),
Windows2000Workstation(Windows2000),
WindowsXp(Windows),
WindowsVista(Windows),
Windows7(Windows),
Windows95(Windows),
Windows98(Windows),
Unix(OS) {
#Override
public boolean supportsXWindows() {
return true;
}
},
Linux(Unix),
AIX(Unix),
HpUx(Unix),
SunOs(Unix),
;
private OsType parent = null;
private OsType(OsType parent) {
this.parent = parent;
}
}
The article show cases lots of little tricks you can pull off with this set up.
I think this answer would be an excellent solution for you. With a type hierarchy like this:
public enum Component {
Interior(Part.Switch),
Exterior(Part.Switch),
DoorSensor(Part.SecuritySensor),
LeakSensor(Part.SecuritySensor),
MotionSensor(Part.SecuritySensor),
Camera(Part.Camera);
private final Part kindOf;
Component(Part kindOf) {
this.kindOf = kindOf;
}
enum Part {
Switch, SecuritySensor, Camera
}
}
More detail can be found in Chapter Enum from Effective Java 2nd Edition.
It seems unusual that you want to express this with an enumeration as opposed to inheritance. The thing with enumerations is that they're essentially compile-time constants, and if you wanted to generate more information in your hierarchy, you'd have to add more enumerations.
That can get messy, fast. It's also slightly contradictory to the real purpose of enumerations - as predefined constants instead of hierarchical entities.
What I propose is using an abstract class called CategoryBase in which to draw everything out of. Then, create your inheritance tree based off of that.
Here's a diagram:
The bulk of the work is really holding properties, and we don't ever expect those properties to be changed once created, so we can allow our abstract class to hold them. We've also set them as final, so they can't be modified, either.
public abstract class CategoryBase {
protected final int ranking;
protected final String name;
protected final SubCategory[] subCategories;
protected CategoryBase(int ranking, String name, SubCategory... subCategories) {
this.ranking = ranking;
this.name = name;
this.subCategories = subCategories;
}
public int getRanking() {
return ranking;
}
public String getName() {
return name;
}
public SubCategory[] getSubCategories() {
return subCategories;
}
}
From there, we can start basing our marker classes off of this - including SubCategory, since it's really just a holder of information that's represented in a different way.
This would also make writing the marker classes straightforward and simple. For example, here's Camera:
public class Camera extends CategoryBase {
protected Camera(int ranking, String name) {
super(ranking, name);
}
}
It's got a striking similarity to SubCategory - a SubCategory doesn't have any nested SubCategorys, so we don't pass in anything to the vararg portion of the constructor.
For something that does have SubCategorys, we need to instantiate them on construction. Here's SecuritySensor as an example.
public class SecuritySensor extends CategoryBase {
public SecuritySensor(int ranking, String name) {
super(ranking, name,
new SubCategory(1, "Door Sensor"),
new SubCategory(2, "Leak Sensor"),
new SubCategory(3, "Motion Sensor"));
}
}
This approach gives you some flexibility around ranking as well - if you wanted to be able to specify the exact ranking of the subcategories at runtime, you'd replace this constructor with one that supported the vararg signature.
you can do something like the code below. but that is probably not quite what you want. you could add the child enums to the constructor for the parent enum like here.
enum Stuff {
Swich,Sensor,Camera;
enum swich {
interior,exterior;
enum Where {
bathroom,kitchen
}
}
enum sensor {
door,leak,motion
}
}
Perhaps reconsider and do use integers here. However, instead of basing them on a decimal system (100, 200, 300,... for first level; 1, 2, 3,... for second level) base them on a binary representation.
// top-level
public static final int SWITCH = 1 << 16;
public static final int SECURITY_SENSOR = 2 << 16;
public static final int CAMERA = 4 << 16;
// sub-types of 'switch'
public static final int INTERIOR = SWITCH | 1;
public static final int EXTERIOR = SWITCH | 2;
// sub-types of 'security sensor'
public static final int DOOR_SENSOR = SECURITY_SENSOR | 1;
public static final int LEAK_SENSOR = SECURITY_SENSOR | 2;
public static final int MOTION_SENSOR = SECURITY_SENSOR | 4;
This allows you to do a weak form of inheritance testing:
if (value == SWITCH) {
// value is a switch, but not interior or exterior
} else if (value & SWITCH != 0) {
// value is interior or exterior
}
Does following code meet your request?
public enum Category {Switch, ...}
public enum SubCategory {Interior, ...}
Which ORM supports a domain model of immutable types?
I would like to write classes like the following (or the Scala equivalent):
class A {
private final C c; //not mutable
A(B b) {
//init c
}
A doSomething(B b) {
// build a new A
}
}
The ORM has to initialized the object with the constructor. So it is possible to check invariants in the constructor. Default constructor and field/setter access to intialize is not sufficient and complicates the class' implementation.
Working with collections should be supported. If a collection is changed it should create a copy from the user perspective. (Rendering the old collection state stale. But user code can still work on (or at least read) it.) Much like the persistent data structures work.
Some words about the motivation. Suppose you have a FP-style domain object model. Now you want to persist this to a database. Who do you do that? You want to do as much as you can in a pure functional style until the evil sides effect come in. If your domain object model is not immutable you can for example not share the objects between threads. You have to copy, cache or use locks. So unless your ORM supports immutable types your constrainted in your choice of solution.
UPDATE: I created a project focused on solving this problem called JIRM:
https://github.com/agentgt/jirm
I just found this question after implementing my own using Spring JDBC and Jackson Object Mapper. Basically I just needed some bare minimum SQL <-> immutable object mapping.
In short I just use Springs RowMapper and Jackson's ObjectMapper to map Objects back and forth from the database. I use JPA annotations just for metadata (like column name etc...). If people are interested I will clean it up and put it on github (right now its only in my startup's private repo).
Here is a rough idea how it works here is an example bean (notice how all the fields are final):
//skip imports for brevity
public class TestBean {
#Id
private final String stringProp;
private final long longProp;
#Column(name="timets")
private final Calendar timeTS;
#JsonCreator
public TestBean(
#JsonProperty("stringProp") String stringProp,
#JsonProperty("longProp") long longProp,
#JsonProperty("timeTS") Calendar timeTS ) {
super();
this.stringProp = stringProp;
this.longProp = longProp;
this.timeTS = timeTS;
}
public String getStringProp() {
return stringProp;
}
public long getLongProp() {
return longProp;
}
public Calendar getTimeTS() {
return timeTS;
}
}
Here what the RowMapper looks like (notice it mainly delegats to Springs ColumnMapRowMapper and then uses Jackson's objectmapper):
public class SqlObjectRowMapper<T> implements RowMapper<T> {
private final SqlObjectDefinition<T> definition;
private final ColumnMapRowMapper mapRowMapper;
private final ObjectMapper objectMapper;
public SqlObjectRowMapper(SqlObjectDefinition<T> definition, ObjectMapper objectMapper) {
super();
this.definition = definition;
this.mapRowMapper = new SqlObjectMapRowMapper(definition);
this.objectMapper = objectMapper;
}
public SqlObjectRowMapper(Class<T> k) {
this(SqlObjectDefinition.fromClass(k), new ObjectMapper());
}
#Override
public T mapRow(ResultSet rs, int rowNum) throws SQLException {
Map<String, Object> m = mapRowMapper.mapRow(rs, rowNum);
return objectMapper.convertValue(m, definition.getObjectType());
}
}
Now I just took Spring JDBCTemplate and gave it a fluent wrapper. Here are some examples:
#Before
public void setUp() throws Exception {
dao = new SqlObjectDao<TestBean>(new JdbcTemplate(ds), TestBean.class);
}
#Test
public void testAll() throws Exception {
TestBean t = new TestBean(IdUtils.generateRandomUUIDString(), 2L, Calendar.getInstance());
dao.insert(t);
List<TestBean> list = dao.queryForListByFilter("stringProp", "hello");
List<TestBean> otherList = dao.select().where("stringProp", "hello").forList();
assertEquals(list, otherList);
long count = dao.select().forCount();
assertTrue(count > 0);
TestBean newT = new TestBean(t.getStringProp(), 50, Calendar.getInstance());
dao.update(newT);
TestBean reloaded = dao.reload(newT);
assertTrue(reloaded != newT);
assertTrue(reloaded.getStringProp().equals(newT.getStringProp()));
assertNotNull(list);
}
#Test
public void testAdding() throws Exception {
//This will do a UPDATE test_bean SET longProp = longProp + 100
int i = dao.update().add("longProp", 100).update();
assertTrue(i > 0);
}
#Test
public void testRowMapper() throws Exception {
List<Crap> craps = dao.query("select string_prop as name from test_bean limit ?", Crap.class, 2);
System.out.println(craps.get(0).getName());
craps = dao.query("select string_prop as name from test_bean limit ?")
.with(2)
.forList(Crap.class);
Crap c = dao.query("select string_prop as name from test_bean limit ?")
.with(1)
.forObject(Crap.class);
Optional<Crap> absent
= dao.query("select string_prop as name from test_bean where string_prop = ? limit ?")
.with("never")
.with(1)
.forOptional(Crap.class);
assertTrue(! absent.isPresent());
}
public static class Crap {
private final String name;
#JsonCreator
public Crap(#JsonProperty ("name") String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
}
Notice in the above how easy it is to map any query into immutable POJO's. That is you don't need it 1-to-1 of entity to table. Also notice the use of Guava's optionals (last query.. scroll down). I really hate how ORM's either throw exceptions or return null.
Let me know if you like it and I'll spend the time putting it on github (only teste with postgresql). Otherwise with the info above you can easily implement your own using Spring JDBC. I'm starting to really dig it because immutable objects are easier to understand and think about.
Hibernate has the #Immutable annotation.
And here is a guide.
Though not a real ORM, MyBatis may able to do this. I didn't try it though.
http://mybatis.org/java.html
AFAIK, there are no ORMs for .NET supporting this feature exactly as you wish. But you can take a look at BLTookit and LINQ to SQL - both provide update-by-comparison semantics and always return new objects on materialization. That's nearly what you need, but I'm not sure about collections there.
Btw, why you need this feature? I'm aware about pure functional languages & benefits of purely imutable objects (e.g. complete thread safety). But in case with ORM all the things you do with such objects are finally transformed to a sequence of SQL commands anyway. So I admit the benefits of using such objects are vaporous here.
You can do this with Ebean and OpenJPA (and I think you can do this with Hibernate but not sure). The ORM (Ebean/OpenJPA) will generate a default constructor (assuming the bean doesn't have one) and actually set the values of the 'final' fields. This sounds a bit odd but final fields are not always strictly final per say.
SORM is a new Scala ORM which does exactly what you want. The code below will explain it better than any words:
// Declare a model:
case class Artist ( name : String, genres : Set[Genre] )
case class Genre ( name : String )
// Initialize SORM, automatically generating schema:
import sorm._
object Db extends Instance (
entities = Set() + Entity[Artist]() + Entity[Genre](),
url = "jdbc:h2:mem:test"
)
// Store values in the db:
val metal = Db.save( Genre("Metal") )
val rock = Db.save( Genre("Rock") )
Db.save( Artist("Metallica", Set() + metal + rock) )
Db.save( Artist("Dire Straits", Set() + rock) )
// Retrieve values from the db:
val metallica = Db.query[Artist].whereEqual("name", "Metallica").fetchOne() // Option[Artist]
val rockArtists = Db.query[Artist].whereEqual("genres.name", "Rock").fetch() // Stream[Artist]