Say i have the below JPA method :
public List<FrequencyCode> findAllByNameContainingAndAllowExplicitDosingTimesEqualsOrderByName(String name, Boolean allowExplicitDosingTimes);
This method is called by a user filtering a list of these objects with an input field and a select field :
The boolean value can be true, false or null in this case if the user is not making a search with that field. It looks like JPA is ACTUALLY searching for a null value when i would like it to ignore any null values. I have been able to make this combined search work with the below code :
#Override
public List<FrequencyCode> findAllWithFilters(String name, Boolean allowExplicitDosingTimes)
{
if (allowExplicitDosingTimes == null)
{
return ((FrequencyCodeRepository) baseRepository).findAllByNameContainingOrderByName(name);
}
else if (allowExplicitDosingTimes == true)
{
return ((FrequencyCodeRepository) baseRepository).findAllByNameContainingAndAllowExplicitDosingTimesTrueOrderByName(name);
}
else if (allowExplicitDosingTimes == false)
{
return ((FrequencyCodeRepository) baseRepository).findAllByNameContainingAndAllowExplicitDosingTimesFalseOrderByName(name);
}
return null;
}
This works but, obviously, on a page with 8 search options this would become a nightmare. The String parameters do not have this problem because they are actually an empty String when the user doesn't choose a filter. This paired with the Containing keyword, any value contains "" so it behaves as if that parameter is ignored which is exactly what I want for other types. Is there a way for a JPA findAll...() method to simply ignore null parameters?
******SOLUTION******
Here is how i made this work with the help of the accepted answer :
FrequencyCode fc = new FrequencyCode();
fc.setName(name);
fc.setAllowExplicitDosingTimes(allowExplicitDosingTimes);
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("name", match -> match.contains())
.withMatcher("allowExplicitDosingTimes", match -> match.exact())
.withIgnorePaths("id", "uuid")
.withIgnoreNullValues();
Example<FrequencyCode> example = Example.of(fc, matcher);
List<FrequencyCode> frequencyCodes = ((FrequencyCodeRepository) baseRepository).findAll(example);
You HAVE to tell it to ignore any ID fields or really any other fields you do not intend to search with but this is INCREDIBLY powerful!
Thanks!
You can use Example like this
#Override
public List<FrequencyCode> findAllWithFilters(String name, Boolean allowExplicitDosingTimes) {
FrequencyCode fc = new FrequencyCode();
//I assume that you have setters like bellow
fc.setName(name);
fc.setAllowExplicitDosingTimes(allowExplicitDosingTimes);
ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreNullValues();
Example<FrequencyCode> example = Example.of(fc, matcher);
return ((FrequencyCodeRepository) baseRepository).findAll(example);
}
Related
Is it possible to have a condition like an if-else or a Ternary Operator inside the
#Mapping(expression="java(...)")
I have a method that returns the last item of an ArrayList, but in case the list is empty it returns null. I need a condition, so in case I receive the item I can use it, or in case it is null it will map null.
public static MyObjectDetail getLastOne(MyObject myObject) {
List<MyObjectDetail> details = myObject.getMyObjectDetails();
if(details.isEmpty()) {
return null;
} else {
return myObject.getLastDetail(myObject);
}
}
This is the #Mapping that I currently use and it works fine if the list is not empty.
#Mapping(expression = "java(MyObjectDetailMapper.getLastOne(myObject).getNumber())", target = "number"),
Solution:
#Mapping(expression = "java(null == MyObjectDetailMapper.getLastOne(myObject) ? null : MyObjectDetailMapper.getLastOne(myObject).getNumber())", target = "number"),
I have a piece of code which returns value of one field, but also initializes it:
public Observable<Integer> asObservable() {
if (subject == null) {
subject = BehaviorSubject.createDefault(0);
}
return subject;
}
I'm trying to use Optional class to avoid if statement:
public Observable<Integer> asObservableWithOptional() {
Optional.ofNullable(subject)
.executeIfAbsent(() -> BehaviorSubject.createDefault(0));
return subject;
}
Hovewer I'm still not happy with this code. Is there a way to turn this methos into one with one statement only? Something similar to following won't work because subject have not been initialized during call to ofNullable factory method:
return Optional.ofNullable(subject)
.executeIfAbsent(() -> BehaviorSubject.createDefault(0))
.get();
Note: I'm not using original Java8 API, but aNNiMON port of this API https://github.com/aNNiMON/Lightweight-Stream-API.
How about
return subject = Optional.ofNullable(subject).orElseGet(() -> BehaviorSubject.createDefault(0));
of course, you can use a ternary conditional operator instead of creating an Optional just to discard it immediately:
return subject != null ? subject : (subject = BehaviorSubject.createDefault(0));
I would suggest something like this :
return (subject == null ? (subject = BehaviorSubject.createDefault(0)) : subject);
I am parsing input JSON. For a field, there are 3 possibilities:
the field is absent;
the value is set to null;
the value is set to something valid.
Different behavior is implemented: for an absent value in the JSON, the default value is inserted into the database; for a null value in the JSON, a null value is inserted into the database.
I thought about Optional to model this:
public class Data {
private Optional<String> field;
}
Which of the following two options make most sense?
If field is null, the field was absent in the JSON. If field is Optional.empty, the field is null in the JSON.
If field is null, the field was null in the JSON. If field is Optional.empty, the field is absent in the JSON.
FWIW, I am using Jackson with module jackson-datatype-jdk8 to parse the input JSON.
I think you shouldn't use Optional for this scenario. As #dkatzel has mentioned in his answer, it's meant to be used as an API return value more than as a field.
Despite this academic discussion, you can accomplish what you want simply by initializing fields in your Data class to their default values:
public class Data {
private String field = DEFAULT_VALUE;
}
And then let Jackson do the rest.
EDIT as per OP's comment:
When your JSON comes with a null value for the field, Jackson will set it to null, and that's what will be stored in the database.
When your JSON does not contain the field, the DEFAULT_VALUE will be automatically loaded in your Data instance.
And when your JSON does actually contain a value for the field, Jackson will set it, and that value will reach the database.
EDIT 2, considering OP's requirement to find out if the field was either filled in, set to null or was absent in the input JSON, after parsing the JSON input:
If, after parsing the input JSON, you need to know whether the field was either filled in, set to null or was absent, then consider this example, which shows the approach I'd take:
public class Data {
private String field1 = "hello";
private Integer field2 = 10;
private Double field3 = 3.75;
private static final Data DEFAULTS = new Data(); // defaults will be kept here
public String getField1() {
return this.field1;
}
public void setField1(String field1) {
this.field1 = field1;
}
public Integer getField2() {
return this.field2;
}
public void setField2(Integer field2) {
this.field2 = field2;
}
public Double getField3() {
return this.field3;
}
public void setField3(Double field3) {
this.field3 = field3;
}
#Override
public String toString() {
return "Data [field1=" + this.field1 +
", field2=" + this.field2 +
", field3=" + this.field3 + "]";
}
public boolean isDefault(Function<Data, Object> getter) {
Object defaultProperty = getter.apply(DEFAULTS);
Object actualProperty = getter.apply(this);
return defaultProperty != null // needed to support fields with no default value
&& defaultProperty.equals(actualProperty);
}
public boolean isNull(Function<Data, Object> getter) {
return getter.apply(this) == null;
}
public boolean isSet(Function<Data, Object> getter) {
return !this.isNull(getter) && !this.isDefault(getter);
}
}
Here I've used a private static attribute to hold your Data's default values and 3 methods to query any field state (default, null or set). In order to determine which field to query, these methods receive a Function<Data, Object>, which are given a Data instance and return an Object that is supposed to be the desired field. (If you stop to think it, getters can be seen as functions that take the instance as input and return a specific field of the instance).
So later, when you need to know how a certain field arrived in your JSON input, just use those 3 query methods to find out:
ObjectMapper m = new ObjectMapper();
String json = "{\"field1\":null,\"field2\":20}";
Data data = m.readValue(json, Data.class);
System.out.println(data); // Data [field1=null, field2=20, field3=3.75]
System.out.println("field1 default ? " + data.isDefault(Data::getField1)); // false
System.out.println("field1 null ? " + data.isNull(Data::getField1)); // true
System.out.println("field1 set ? " + data.isSet(Data::getField1)); // false
System.out.println("field2 default ? " + data.isDefault(Data::getField2)); // false
System.out.println("field2 null ? " + data.isNull(Data::getField2)); // false
System.out.println("field2 set ? " + data.isSet(Data::getField2)); // true
System.out.println("field3 default ? " + data.isDefault(Data::getField3)); // true
System.out.println("field3 null ? " + data.isNull(Data::getField3)); // false
System.out.println("field3 set ? " + data.isSet(Data::getField3)); // false
I would say that the first option makes the most semantic sense. It also potentially allows for easier computation.
Where a field in java is null, it is implied that a value is missing, which matches the first option.
I suggest that you store these fields in a hash-map where the key is the JSON field name and the value is the JSON field's value. I also suggest you don't use an optional here (as it can add an unnecessary layer of complexity), and instead use either a null or non-null object in the hashmap.
HashMap<String, Value> jsonFields = new HashMap<String, Value>();
boolean hasField1 = false;
Value field1Value = null;
if(jsonFields.contains("field1"){ // It is present in the JSON file
field1Value = jsonFields.get("field1"); // "null" here would mean that the JSON field was set to "null"
hasField1 = true;
}
The second choice makes more sense to me. null means null and empty means not present.
However, Optional shouldn't really be used as a field. It's supposed to be used as an API return value.
Could you instead store the data in a Map that allows null values? And if the key (your field) isn't present in the map, then return Optional.empty ?
Neither? I would annotate my POJO fields with #DefaultValue(). Then your possibilities are a null value or a non-null value specified in JSON, or the default if the field was omitted from JSON. And you can then just persist the POJO without any special per-field analysis.
If you are dealing with Object instead of String, here's a solution I find elegant:
use Optional.empty(); if there is no value
use Optional.of(value) if there is a value
use Optional.of(specialValue) if the value is null
where specialValue is a static singleton you can easily test, for instance: ObjectUtils.NULL (from commons.lang).
Then you can easily test your optional:
if (optional.isPresent()) {
if (ObjectUtils.NULL.equals(optional.get())) {
// value is there and null
} else {
// value is there and not null
}
} else {
// value is not there
}
I am receiving list of fields. Near About to 60 fields.
From that I have to check 50 fields that are they null or empty, if not then I ll have to add them also in DB table.
Right now I am doing it manually using if condition. I am just thinking to do so, not implemented still yet.
Is there any better option then it ?
My Code :
if(ValidateData.checkIsNullOrEmpty(command.getSubscriptionStartYear())){
}
if(ValidateData.checkIsNullOrEmpty(command.getSubscriptionPeriod())){
}
if(ValidateData.checkIsNullOrEmpty(command.getExpectedArrivalTimeOfIssues())){
}
.....
.....
if(ValidateData.checkIsNullOrEmpty(command.getMaxNoOfClaims())){
}
Here command is class which receives Data from source.
Here ValidateData is a class :
It's method definition :
public static boolean checkIsNullOrEmpty(Integer arg){
if(arg != null) return true;
return false;
}
public static boolean checkIsNullOrEmpty(String arg){
if(!arg.trim().equals("") || !arg.trim().equals(" ") || arg.trim() != null) return true;
return false;
}
If anyone guide me or suggest me that is there any better option available ??
create a function like this:
public static bool AllNull(object... something)
{
for(var v :something)
if(v!=null){
if(v instanceof Integer)
// do integer validation
}else
//Err msg
}
Then you could call it like this:
if (AllNull(obj1, obj2, obj3, obj4, obj5, obj6))
{
// ...
}
if you want to be specific, separate strings and integers and make separate function like this one for each type you need
Edit
as i understod from your comment, u don't know varargs
varargs are useful for any method that needs to deal with an
indeterminate number of objects. One good example is String.format.
if you can edit command, you can mark each field that you want to check null with #NotNull, then use java reflect api to get all fields marked with #NotNull, and check whether some fields null or not
I think best solution for your problem is using Java Reflect.
Here is sample code to validate all field of an instance by Java Reflect.
Example I have one instance(pojo) of object PojoObj.
PojoObj pojo = new PojoObj("one1", 2, null, 4, "five", "Six");
Validate all fields by Java Reflect.
Class<PojoObj> aClass = PojoObj.class;
Field[] fields = aClass.getDeclaredFields();
for(Field field : fields) {
Object value = field.get(pojo);
Object type = field.getType();
if(value == null) {
System.out.println(field.getName() + " is null");
} else {
System.out.println(field.getName() + " is instanceof " + type + " and value = " + value);
}
}
Output:
fieldOne is instanceof class java.lang.String and value = one1
fieldTwo is instanceof long and value = 2
fieldThree is null
fieldFour is instanceof int and value = 4
fieldFive is instanceof class java.lang.String and value = five
fieldSix is instanceof class java.lang.String and value = Six
I have two lists of type object with data , the first one is principal entity and the second is dependent entity.
In addition I have key table that relate between the principal and depended entity objects.
In the first for statement I get one instance of type object and then I go and loop on every instance of the second entity and trying to find
Match between them (i think exponential problem…) ,if match is find update the principal entity with the reference object .
The following code is working but I check it from performance perspective and it's not working in efficient way.
Do you have an idea/tips how to improve this code from perforce aspect.
In the JVM monitor I found that EntityDataCreator.getInstanceValue have a problem.
This is the method start
// start with the principal entity
for (Object principalEntityInstance : principalEntityInstances) {
List<Object> genObject = null;
Object refObject = createRefObj(dependentMultiplicity);
// check entries in dependent entity
for (Object dependentEntityInstance : toEntityInstances) {
boolean matches = true;
for (String[] prop : propertiesMappings) {
// Get properties related keys
String fromProp = prop[0];
String toProp = prop[1];
Object fromValue = EntityDataCreator.getInstanceValue(fromProp, principalEntityInstance);
Object toValue = EntityDataCreator.getInstanceValue(toProp, dependentEntityInstance);
if (fromValue != null && toValue != null) {
if (!fromValue.equals(toValue)) {
matches = false;
break;
}
}
}
if (matches) {
// all properties match
if (refObject instanceof List) {
genObject = (List<Object>) refObject;
genObject.add(dependentEntityInstance);
refObject = genObject;
} else {
refObject = dependentEntityInstance;
break;
}
}
}
if (refObject != null) {
EntityDataCreator.createMemberValue(principalEntityInstance, navigationPropName, refObject);
}
}
public static Object getInstanceValue(String Property, Object EntityInstance) throws NoSuchFieldException,
IllegalAccessException {
Class<? extends Object> EntityObj = EntityInstance.getClass();
Field Field = EntityObj.getDeclaredField(Property);
Field.setAccessible(true);
Object Value = Field.get(EntityInstance);
Field.setAccessible(false);
return Value;
}
my guess would be your best bet is to go through both lists once, prepare all data that you need in hashtables, then do one iteration. this way, your problem becomes N+M instead of N*M
edit
Map<String,List<Object>> principalMap = new HashMap<String,List<Object>>();
for (Object principalEntityInstance : principalEntityInstances) {
List<String> keys = getKeysFor(principalEntityInstance);
for(String key : keys) {
List<Object> l = principalMap.get(key);
if(l==null) {
l = new ArrayList<Object>();
principalMap.put(key,l);
}
l.add(principalEntityInstance);
}
}
the do the same for dependentEntityInstance - this way, your searches will be much faster.
I might be misunderstanding your question, but I would suggest defining an equals method for your entities and a hashing method for them, so that you can leverage all the goodness that java already has for searching and matching entities already.
When at all possible rely on Java's infrastructure I think, Sun/Oracle spent a long time making it really fast.