I have an API endpoint where I am receiving JSON files, and I am creating an object from the files. I also have another pre-existing object, and I am trying to check if certain values in the received JSON match certain values in my existing object. If the fields match I will continue to process the file further, if not I will scrap it. My thoughts so far is just to have if statements checking each value, but is there a better way to do this? Or are if statements ok?
Very quick code example of what I mean by just using if statements.
public boolean compareObjects(recievedObject, existingObject) {
if( !(recievedObject.getName().equals(existingObject.getName()))) {
//true
} else if( !(recievedObject.getLocation().equals(existingObject.getLocation())) ) {
return false;
}
// else if ... etc
return true;
}
Note that I am not trying to check if the received file has all the required JSON fields, just that a few particular fields have certain values.
Edit:
The JSON will be a very flat structure e.g
{
"name": "name",
"location": "location",
...
}
So my object will be pretty basic
public class recievedObject {
String location;
String name;
public String getLocation() {
return location;
}
public String getName() {
return name;
}
}
What you can do to avoid lot of it-else statements is to create some validation abstraction.
interface Validator<A, B> {
boolean validate(A receivedObject, B existingObject);
}
Then for each if create new implementation of Validator.
class NameValidator implements Validator<Expeceted, Received> {
#Override
public boolean validate(Expeceted receivedObject, Received existingObject) {
return existingObject.getName().equals(receivedObject.getName());
}
}
class LocationValidator implements Validator<Expeceted, Received> {
#Override
public boolean validate(Expeceted receivedObject, Received existingObject) {
return existingObject.getLocation().equals(receivedObject.getLocation());
}
}
You can create list of such a validators
List<Validator<Expeceted, Received>> validators = Arrays.asList(
new NameValidator(),
new LocationValidator()
);
And finally your compare method could simply iterate through all validators.
public boolean compareObjects(Received recievedObject, Expeceted expecetedObject) {
for (Validator<Expeceted, Received> validation : validators) {
if (! validation.validate(expecetedObject, recievedObject)) {
return false;
}
}
return true;
}
This way you can simply add new validators later and keep compare method untouched.
define a method similar to 'equal' for your class and at the endpoint check the existingObject.check(receivedObject), add import java.util.Objects to your class
public boolean check(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RecievedObject receivedObject=(RecievedObject) o;
//add based on the logic you want
return Objects.equals(location, receivedObject.location) &&
Objects.equals(name, receivedObject.name);
}
Related
This would mean that the class was initialized, but the variables were not set.
A sample Class:
public class User {
String id = null;
String name = null;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The actual class is huge that I prefer not to check if(xyz == null) for each of the variables.
Another non-reflective solution for Java 8, in the line of paxdiabo's answer but without using a series of if's, would be to stream all fields and check for nullness:
return Stream.of(id, name)
.allMatch(Objects::isNull);
This remains quite easy to maintain while avoiding the reflection hammer.
Try something like this:
public boolean checkNull() throws IllegalAccessException {
for (Field f : getClass().getDeclaredFields())
if (f.get(this) != null)
return false;
return true;
}
Although it would probably be better to check each variable if at all feasible.
This can be done fairly easily using a Lombok generated equals and a static EMPTY object:
import lombok.Data;
public class EmptyCheck {
public static void main(String[] args) {
User user1 = new User();
User user2 = new User();
user2.setName("name");
System.out.println(user1.isEmpty()); // prints true
System.out.println(user2.isEmpty()); // prints false
}
#Data
public static class User {
private static final User EMPTY = new User();
private String id;
private String name;
private int age;
public boolean isEmpty() {
return this.equals(EMPTY);
}
}
}
Prerequisites:
Default constructor should not be implemented with custom behavior as that is used to create the EMPTY object
All fields of the class should have an implemented equals (built-in Java types are usually not a problem, in case of custom types you can use Lombok)
Advantages:
No reflection involved
As new fields added to the class, this does not require any maintenance as due to Lombok they will be automatically checked in the equals implementation
Unlike some other answers this works not just for null checks but also for primitive types which have a non-null default value (e.g. if field is int it checks for 0, in case of boolean for false, etc.)
If you want this for unit testing I just use the hasNoNullFieldsOrProperties() method from assertj
assertThat(myObj).hasNoNullFieldsOrProperties();
How about streams?
public boolean checkFieldsIsNull(Object instance, List<String> fieldNames) {
return fieldNames.stream().allMatch(field -> {
try {
return Objects.isNull(instance.getClass().getDeclaredField(field).get(instance));
} catch (IllegalAccessException | NoSuchFieldException e) {
return true;//You can throw RuntimeException if need.
}
});
}
"Best" is such a subjective term :-)
I would just use the method of checking each individual variable. If your class already has a lot of these, the increase in size is not going to be that much if you do something like:
public Boolean anyUnset() {
if ( id == null) return true;
if (name == null) return true;
return false;
}
Provided you keep everything in the same order, code changes (and automated checking with a script if you're paranoid) will be relatively painless.
Alternatively (assuming they're all strings), you could basically put these values into a map of some sort (eg, HashMap) and just keep a list of the key names for that list. That way, you could iterate through the list of keys, checking that the values are set correctly.
I think this is a solution that solves your problem easily: (return true if any of the parameters is not null)
public boolean isUserEmpty(){
boolean isEmpty;
isEmpty = isEmpty = Stream.of(id,
name)
.anyMatch(userParameter -> userParameter != null);
return isEmpty;}
Another solution to the same task is:(you can change it to if(isEmpty==0) checks if all the parameters are null.
public boolean isUserEmpty(){
long isEmpty;
isEmpty = Stream.of(id,
name)
.filter(userParameter -> userParameter != null).count();
return isEmpty > 0
}
The best way in my opinion is Reflection as others have recommended. Here's a sample that evaluates each local field for null. If it finds one that is not null, method will return false.
public class User {
String id = null;
String name = null;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isNull() {
Field fields[] = this.getClass().getDeclaredFields();
for (Field f : fields) {
try {
Object value = f.get(this);
if (value != null) {
return false;
}
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return true;
}
public static void main(String args[]) {
System.out.println(new User().isNull());
}
}
Field[] field = model.getClass().getDeclaredFields();
for(int j=0 ; j<field.length ; j++){
String name = field[j].getName();
name = name.substring(0,1).toUpperCase()+name.substring(1);
String type = field[j].getGenericType().toString();
if(type.equals("class java.lang.String")){
Method m = model.getClass().getMethod("get"+name);
String value = (String) m.invoke(model);
if(value == null){
... something to do...
}
}
Best for me is
Stream.of(getClass().getDeclaredMethods()).allMatch(Objects::isNull);
It can be used in a custom annotation + annotation processor to automagically define a boolean isNull() method on the annotated classes.
Based on Irkwz's answer, but a different approach:
public class SomeClass{
private String field1;
private String field2;
private ComplexField field3;
private String field4;
private Integer field15;
public boolean isNullAllFields() {
return Stream.of(this.getClass().getDeclaredFields()).anyMatch(element -> (element != null));
}
}
And the end of the day u invoke isNullAllFields method to figure out wheter the object fields are empty.
If you want to do the opposite i.e check if some/all members of class are non-non, the check this answer.
In order to make sure that certain members of the class are always non-null, we can use lombok #NonNull annotation on the individual fields of the class.
import lombok.Data;
import lombok.NonNull;
#Data
public class DataClass {
#NonNull
private String data1;
private int data2;
#NonNull
private String data3;
#NonNull
private String data4;
#NonNull
private String data5;
private String data6;
DataClass(String data1,...) {
// constructor
}
}
Easiest way is to convert the class to a map and get its keys and with stream check if any or all key's values are null or not, you can take input from user as well whether they want to check for specific set of keys only!
Below is the code to check whether any of the key's value has null, you can change stream config to all match or any match as per your requirement
Just replace isNullOrEmpty method i have used with proper null or empty check condition for that particular collection
public boolean checkIfAnyFieldIsNull(Object instance, Set<String> fields){
try {
Map<String, Object> instanceMap = new Gson().fromJson(new GsonBuilder().serializeNulls().create().toJson(instance), Map.class);
if(!isNullorEmpty(instanceMap)) {
fields = isNullorEmpty(fields) ? instanceMap.keySet() : fields;
return fields.stream().anyMatch(curField -> isNull(instanceMap.get(curField)));
}else{
return false;
}
}catch (Exception e){
return false;
}
}
}
Try this method once, its works for me!!
private fun checkIfAnyDataIsNull(model: YourModelCass): Boolean {
return Stream.of<Any>(
model.date,
model.merchantName,
model.payment,
).allMatch(Objects::isNull)
}
You can use the simple solution:
if(user.equals(new User()){
//your processing goes here
}
I am working on a Spring Boot application and I have the following doubt.
I have this service method (that works fine) that insert an object into the DB calling the repository:
#Override
#Transactional
public CoinDTO createCoin(CoinDTO coin) throws DuplicateException {
Coin checkCoinExists = coinRepository.findByCode(coin.getCode());
if (checkCoinExists != null) {
String MsgErr = String.format("Coin %s already registered in the system !!! "
+ "Impossible to use POST", coin.getCode());
log.warning(MsgErr);
throw new DuplicateException(MsgErr);
}
Coin result = coinRepository.save(conversionService.convert(coin,Coin.class));
return conversionService.convert(result,CoinDTO.class);
}
As you can see the save() methjod return the inserted Coin object (that is an Hibernate entity class mapping my table). The service method than convert this Coin object into the CoinDTO object in order to return the DTO object instead the entity instance. It works fine and it is the expected behavior.
Now I created this second service method that simply retrieve the list of all the Coin objects and must return the list of the related CoinDTO objects:
#Override
public List<CoinDTO> getCoinList() {
List<Coin> coinsList = this.coinRepository.findAll();
return null;
}
and here I have the following doubt: I think that I can implement thid ENTITY to DTO conversion behavior iterating on the coinsList element, converting each element of the list one by one and then adding it to a new List list. It should work
Exist some more modern and smarter way to do it? Maybe using lambda function? Can you help me to implement this behavior in a modern and a smart way?
You may create an generic abstract class like this:
public abstract class AbstractConverter<T, DTO> {
public abstract T fromDto(DTO dto);
public abstract DTO toDTO(T t);
public List<T> fromDTOs(List<DTO> dtos) {
if (dtos == null || dtos.isEmpty()) {
return null;
} else {
return dtos.stream().map(this::fromDTO).collect(Collectors.toList());
}
}
public List<DTO> toDTOs(List<T> ts) {
if (ts == null || ts.isEmpty()) {
return null;
} else {
return ts.stream().map(this::toDTO).collect(Collectors.toList());
}
}
}
Then create another class that implements the aforecreated abstract class by assigning your desired values like this:
#Component(value = "coinConverter")
public class CoinConverter extends AbstractConverter<Coin, CoinDTO> {
#Override
public Coin fromDTO(CoinDTO dto) {
if (dto == null) {
return null;
} else {
Coin coin = new Coin();
// Assign all values you wanted to consume
// of the following form
// coin.setYourAttribite(dto.getYourAttribute())
return coin;
}
}
#Override
public CoinDTO toDTO(Coin coin) {
if (t == null) {
return null;
} else {
CoinDTO coinDTO = new CoinDTO();
// Assign all values you wanted to expose
// of the following form
// coinDTO.setYourAttribite(coin.getYourAttribute())
return coinDTO;
}
}
}
In controller layer you may change your existing code by this one:
#Autowired
#Qualifier("coinConverter")
AbstractConverter<Coin, CoinDTO> abstractConverter;
#Override
public List<CoinDTO> getCoinList() {
List<Coin> coinsList = this.coinRepository.findAll();
return abstractConverter.toDTOs(cointList);
}
This way your code is flexible to add more converters without changing the existing ones.
As far as I understand, you are looking for a way that makes the conversion process shorter and more convenient. if so use ModelMapper class in this case, read this http://modelmapper.org/ documentation, ModelMapper uses TypeTokens to allow mapping of generic parameterized types.
Not sure if I understood your question, but is the following what you are looking for:
#Override
public List<CoinDTO> getCoinList() {
return this.coinRepository.findAll().stream()
.map(coin -> conversionService.convert(coin, CoinDTO.class))
.collect(Collectors.toList());
}
I want to reduce the validations, maybe using some methods.
I'm delaing with a basic crud, and on the update endpoint, they want to update just one field at once, and giving me a arbitrary number of params, can be 1,2 or 10. and they dont want of course to erase the database if a parameter isnt sent.
#PostMapping("/updateTask")
#ResponseBody
public String updateTask(#RequestBody Task sentTask) {
Task dbTask = null;
try {
dbTask = taskDao.findByIdTask(sentTask.getIdTask());
if(isValid(sentTask.getAuthor())){
dbTask.setAuthor(sentTask.getAuthor());
}
else{
dbTask.setAuthor(dbTask.getAuthor());
}
if(isValid(sentTask.getIdReport())){
dbTask.setIdReport(sentTask.getIdReport());
}
else{
dbTask.setIdReport(dbTask.getIdReport());
}
taskDao.save(dbTask);
} catch (Exception e) {
String response = "{\"data\":
{\"success\":\"false\",\"error\":\"Error updating the task:\"}}";
return response;
}
String response = "{\"data\":{\"success\":\"true\",\"message\":\"Task
updated successfully\",\"Id\":\"" + sentTask.getIdTask() + "\"}}\n";
return response;
}
public boolean isValid(Object data){
if (data == null){
return false;
}
if(data.equals("")){
return false;
}
return true;
}
I want some like this
public void setData(Object sentData, Object dbData){
if (isValid(sentData)){
dbData.setSentData
}
else{
dbData.setDbData
}
}
You can consider using Optional provided in java 8
Optional<String> authorOptional = Optional.ofNullable(sentTask.getAuthor());
if(authorOptional.isPresent()){
dbTask.setAuthor(sentTask.getAuthor());
}else{
dbTask.setAuthor(dbTask.getAuthor());
}
Optional<String> reportOptional = Optional.ofNullable(sentTask.getIdReport());
if(reportOptional.isPresent()){
dbTask.setIdReport(sentTask.getIdReport());
}else{
dbTask.setIdReport(dbTask.getIdReport());
}
OR
dbTask.setAuthor(Optional.ofNullable(sentTask.getAuthor()).isPresent()?sentTask.getAuthor():dbTask.getAuthor());
dbTask.setIdReport(Optional.ofNullable(sentTask.getIdReport()).isPresent()?sentTask.getIdReport():dbTask.getIdReport());
Now you don't need isValid or setData method
I would recommend business logic related changes should be handled service layer
1) First of all the code like this
else {
dbTask.setIdReport(dbTask.getIdReport());
}
doesn't make any sense as long as property value remains unchanged. So we could easily throw it away.
2) Some reduction could be achieved with following approach
Add following methods:
public void updateTask(Task received, Task existing) {
// run validations and copy only valid values
copyValid(received::getAuthor, existing::setAuthor);
copyValid(received::getReportId, existing::setReportId);
taskDao.save(existing);
}
private <T> void copyValid(Supplier<T> getter, Consumer<T> setter) {
Optional.ofNullable(getter.get())
.map(this::validOrNull)
.ifPresent(setter); // setter will be executed only for non-null values
}
private <T> T validOrNull(T data) {
if (data == null) {
return null;
}
if (data instanceof String && data.equals("")) {
return null; // if data is invalid return null
}
// additional checks for other types can be added here
return data; // otherwise return data as is
}
And adjust controller method like this
#PostMapping("/updateTask")
#ResponseBody
public String updateTask(#RequestBody Task sentTask) {
try {
Task dbTask = taskDao.findByIdTask(sentTask.getIdTask());
updateTask(sentTask, dbTask);
} catch (Exception e) {
// omitted
}
}
P.S. As already mentioned in another answer you should extract your business logic to separate service
I have 3 fields for defining a unique object, e.g.: region, name, platform which are string values.
A list of such objects has to be compared with another list of such objects. I was thinking to create an object for that such as
Class myObject{
private String region;
private String name;
private String platform;
}
and then create a list of them to compare each objects in both the lists. Somebody please provide me a better solution for this problem.
I have two tables with columns, id,region, platform, name, zone, count ,etc and the values repeat in this table. Another table has id, region, platform, name zone. First table gives the list of reserved AWS EC2 instances and second table the list of AWS EC2 instances which are running now. I need to find out if all the reserved instances are currently running or is there anything unutilized.
Can anyone suggest a good solution for this problem.
You need to extend your class definition with and equals() and hashCode() method.
See the following articles: Equality on artima.com & Java Equals & HashCode on ideyatech.com. Google for many more.
You can then use a Set or iterate through a list using equals as the test to help generate a collection of unique objects.
To check if the two objects are equal, you need to override equals() and should override hashCode() also. More detail can be found : here
Below is a sample class MyClazz with a test MyClazzTest to help you understand:
MyClazz
package com.my.test;
public class MyClazz {
private String region;
private String name;
private String platform;
public MyClazz(String region, String name, String platform) {
this.region = region;
this.name = name;
this.platform = platform;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result
+ ((platform == null) ? 0 : platform.hashCode());
result = prime * result + ((region == null) ? 0 : region.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MyClazz other = (MyClazz) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (platform == null) {
if (other.platform != null)
return false;
} else if (!platform.equals(other.platform))
return false;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
return true;
}
}
MyClazzTest
package com.my.test;
import org.junit.Assert;
import org.junit.Test;
public class MyClazzTest {
#Test
public void equalObject() {
MyClazz object = new MyClazz("UK", "Chris", "Window");
MyClazz duplicateObject = new MyClazz("UK", "Chris", "Window");
Assert.assertTrue(object.equals(duplicateObject));
}
#Test
public void notEqualObject() {
MyClazz object = new MyClazz("UK", "Chris", "Window");
MyClazz differentObject = new MyClazz("US", "Chris", "Window");
Assert.assertFalse(object.equals(differentObject));
}
}
For the edited question:
Create a POJO Class with all fields, representing a composite key.
Implement equals and hashCode methods for it.
Create 2 collections of POJOs, filling them with data from tables.
Use one of the methods of CollectionUtils of ApacheCommons to play with your collections. E.g.: CollectionUtils#isSubCollection
We are parsing XML configuration files with JAXB into Java objects. The XML files are versioned and after loading version 1.0 and 2.0 into objects we would like to compare the two objects of the same but unknown type (there are many different configurations for all kinds of things) recursively and their field values and print out the differences.
An object might look as follows.
#XmlRootElement(name = "HelloWorld")
public class HelloWorldConfiguration {
private List<HelloWorldObject> helloWorldObjects = new ArrayList<HelloWorldObject>();
public HelloWorldConfiguration() {
HelloWorldObject o = new HelloWorldObject();
helloWorldObjects.add(o);
helloWorldObjects.add(o);
helloWorldObjects.add(o);
helloWorldObjects.add(o);
helloWorldObjects.add(o);
}
#XmlElement(name = "helloWorldObject")
public List<HelloWorldObject> getHelloWorldObjects() {
return helloWorldObjects;
}
public void setHelloWorldObjects(List<HelloWorldObject> helloWorldObjects) {
this.helloWorldObjects = helloWorldObjects;
}
}
public class HelloWorldObject {
private Stage firstName = new Stage("Tony");
private Stage secondName = new Stage("Stark");
public Stage getFirstName() {
return firstName;
}
public void setFirstName(Stage firstName) {
this.firstName = firstName;
}
public Stage getSecondName() {
return secondName;
}
public void setSecondName(Stage secondName) {
this.secondName = secondName;
}
}
For example we would like to be informed about following changes about the above HelloWorldConfiguration object?
there is additional "HelloWorldObject" item in the list (the item with its attributes must be printed on screen)
the "HelloWorldObject" at the position n has a new "firstName" value (the name of the field or XML element that changed and its value should be printed)
the new "HelloWorldObject" list is shorter by 2 following elements (the missing elements must be printed with all attributes and values)
My questions are as follows.
Would you solve this with reflection on the Java object level or compare the two different XML files?
Are there any libraries out there that already do something like that for me? On XML or Java object level?
Any examples?
Disclaimer. I am the author of the JAXB2 Basics plugin package which includes the JAXB2 Equals plugin.
If you generate your classes from an XML Schema, the JAXB2 Equals plugin might be of use for you in this use case.
The JAXB2 Equals plugin is capable of generating equals methods which do deep structure-traversing value comparison of JAXB class instances:
public boolean equals(Object object) {
final EqualsStrategy strategy = JAXBEqualsStrategy.INSTANCE;
return equals(null, null, object, strategy);
}
public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object object, EqualsStrategy strategy) {
if (!(object instanceof PurchaseOrderType)) {
return false;
}
if (this == object) {
return true;
}
final PurchaseOrderType that = ((PurchaseOrderType) object);
{
USAddress lhsShipTo;
lhsShipTo = this.getShipTo();
USAddress rhsShipTo;
rhsShipTo = that.getShipTo();
if (!strategy.equals(LocatorUtils.property(thisLocator, "shipTo", lhsShipTo), LocatorUtils.property(thatLocator, "shipTo", rhsShipTo), lhsShipTo, rhsShipTo)) {
return false;
}
}
{
USAddress lhsBillTo;
lhsBillTo = this.getBillTo();
USAddress rhsBillTo;
rhsBillTo = that.getBillTo();
if (!strategy.equals(LocatorUtils.property(thisLocator, "billTo", lhsBillTo), LocatorUtils.property(thatLocator, "billTo", rhsBillTo), lhsBillTo, rhsBillTo)) {
return false;
}
}
// ...
return true;
}
I hope you've got the idea. You can provide a "locator" which would track the location of things being compared and a strategy which will do the comparison of individual values.
As the result you can:
Do an in-depth comparison of schema-derived JAXB class instances.
Know what is different (exact values).
Know where are the differences (exact location in the object structure).
And the whole thing is reflection-free and therefore quite fast.
Below is a snippet from another project. This is from one of the tests where I compare object "before" and "after" and log the differences.
final EqualsStrategy strategy = new org.jvnet.hyperjaxb3.lang.builder.ExtendedJAXBEqualsStrategy() {
#Override
public boolean equals(ObjectLocator leftLocator,
ObjectLocator rightLocator, Object lhs, Object rhs) {
if (!super.equals(leftLocator, rightLocator, lhs, rhs)) {
logger.debug("Objects are not equal.");
super.equals(leftLocator, rightLocator, lhs, rhs);
logger.debug("Left: "
+ (lhs == null ? "null" : lhs.toString()));
if (leftLocator != null) {
logger.debug("At [" + leftLocator.getPathAsString()
+ "].");
}
logger.debug("Right: "
+ (rhs == null ? "null" : rhs.toString()));
if (rightLocator != null) {
logger.debug("At [" + rightLocator.getPathAsString()
+ "].");
}
return false;
} else
{
return true;
}
}
};
From the other hand, this approach is not a real "diff" as you may know it from VCS. It only says that something is different, but does not calculate any "shortest edit distance".