Can't store Object in HashMap - java

I'm trying to create a SecureDataContainer with HashMap so defined:
HashMap: ()>
Where KeyCouple is a class defined by me which contains the couple to access to the Vector associated to that couple.
Now when i create a couple of HashMap in this method
private Map<KeyCouple,Vector<E>> DBUsers;
public void createUser(String Id, String passw) throws
UserAlreadyPresent {
if(Id.isEmpty() || passw.isEmpty()) throw new IllegalArgumentException();
if(existsUser(Id)) throw new UserAlreadyPresent(Id);
KeyCouple u = new KeyCouple(Id, passw);
DBUsers.put(u, new Vector<>());
}
Now, in main class, I Run the following code:
private static void testContainer(SecureDataContainer<String> container){
try {
container.createUser("Name","pwd");
} catch (UserAlreadyPresent e) {
System.out.println("User already present");
}
...
To create the user "Name" with the Password "pwd".
But When i put something in the Vector associated to the couple created using my "put" method:
public boolean put(String Owner, String passw, E data) throws NoUserException {
if(Owner == null || passw == null || data == null) throw new NullPointerException();
if(Owner.isEmpty() || passw.isEmpty()) throw new IllegalArgumentException();
KeyCouple user = new KeyCouple(Owner,passw);
if(DBUsers.containsKey(user)){
Vector<E> aux = DBUsers.get(user);
return aux.add(data);
}else{
throw new NoUserException("No user");
}
}
In main class, I call the method:
try {
container.put("Name", "pwd", someData of type E);
} catch (NoUserException e){
abort("no user");
}
and it abort in every case, going even in the catch branch and printing "no user".
What does this means?

You can check the sample KeyCouple class with equals and hashcode.
public class KeyCouple {
private String name;
private String pwd;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KeyCouple keyCouple = (KeyCouple) o;
return Objects.equals(name, keyCouple.name) &&
Objects.equals(pwd, keyCouple.pwd);
}
#Override
public int hashCode() {
return Objects.hash(name, pwd);
}
}

Your passwords are different. You created it with Pwd, and in your main class you use pwd

every use of new creates a new object in the heap.
while you have stored one instance of KeyCouple as key in the hashmap, you are trying to match it with a different instance of KeyCouple. the hash code generated for each instance of user would be different. thus, java is not able to match them. one solution would be to override the hashCode method in KeyCouple Class.
#Override
public int hashCode() {
return Objects.hash(......);
}

You'll need to overwrite the equals and hashcode methods of KeyCouple.
I'd suggest you to use any IDE to auto-generate them for you.
KeyCouple user = new KeyCouple(Owner,passw);
This creates a new user object and you insert this into the map. And the next time you are creating another new Object (which is never equal to the already created Object unless you explicitly override equals/hashcode).
Please refer this for further explanation.
Why do I need to override the equals and hashCode methods in Java?

Related

Best pattern to create a wrapper Constructor

The problem is the following. Given a class GenericConfig which encapsulates a Map<String, Object> to contain several configurations, a class SpecificConfig is desired to have getters to retrieve specific map values.
For example, I want to avoid testing that GenericConfig.getProperties().get(KEY_OF_PROPERTY); is null and getting the value, with the burden of memorizing the key value in the calling method. I want to create a SpecificConfig that is created only if the key is present and that has a getProperty() method.
Example of what I want to avoid:
private final static String KEY_OF_PROPERTY = "key.for.my.value";
public void process(List<GenericConfig> configs) {
for(GenericConfig config: configs) {
String value = config.getProperties().get(KEY_OF_PROPERTY);
if (value != null) {
// do something
}
}
}
This is my attempt:
public final class SpecificConfig extends GenericConfig {
public SpecificConfig(GenericConfig from) {
if(from.getProperties().get(KEY_OF_PROPERTY) != null) {
this.properties = from.getProperties();
} else {
throw new ThisIsNotTheConfigIWant();
}
}
public String getProperty() {
return (String) this.properties.get(KEY_OF_PROPERTY);
}
}
So I can do the following:
public void process(List<GenericConfig> configs) {
for(GenericConfig config: configs) {
try {
SpecificConfig c = new SpecificConfig(config);
// now i can be sure that c is of the required type
// do stuff related to that type
} catch (ThisIsNotTheConfigIWant) { /* ignore this config */ }
}
}
Is throwing a checked exception in the constructor a bad thing in OOP? Does a pattern to solve this problem exist? Is it viable to instantiate null in the constructor instead of throwing an exception.
When calling the constructor it must return an instance of the class, never null. But if you want it to be possible to be null, use a static factory method instead:
public SpecificConfig maybeCreateFrom(GenericConfig c) {
if (<matches>) {
return SpecificConfig(c);
} else {
return null;
}
}
Then on the for-loop you can check for not-null. I think that is generally better than using clunky exceptions for control-flow handling. Though I suspect this is still not the best architecture for you.
Does the class GenericConfig holds a single config or a Map of configs? I would consider just creating methods to fetch configs with the existing keys + doing any null checks. Then you can just call getConfigX() or something.

Checking if received JSON has necessary values in Java

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);
}

avoid everytime check for nonnull and nonempty variables at dto in spring

I have following method which updates user data if the data is nonEmpty or nonNull
public Users updateUser(Users requestBody) throws AppServiceException {
Users user = new Users();
try {
user = userDAO.getUserByUserId(requestBody.getUserId());
if (requestBody.getRole() != null && !requestBody.getRole().isEmpty()) {
user.setRole(requestBody.getRole());
}
if (requestBody.getUserName() != null && !requestBody.getUserName().isEmpty()) {
user.setUserName(requestBody.getUserName());
}
if (requestBody.getChannelType() != null && !requestBody.getChannelType().isEmpty()) {
user.setChannelType(requestBody.getChannelType());
}
if (requestBody.getStatus() != null && !requestBody.getStatus().isEmpty()) {
user.setStatus(requestBody.getStatus());
}
if (requestBody.getDevice() != null) {
user.setDevice(requestBody.getDevice());
}
user.setUpdatedDate(new Date());
user = userDAO.updateUser(user);
} catch (Exception e) {
e.printStackTrace();
throw new AppServiceException(AppServiceException._FAIL_TO_UPDATE);
}
return user;
}
I checked the values for nonNull & isEmpty everytime.
How can I avoid this?
You can use Apache commons lang's StringUtils.isEmpty(java.lang.String)
Checks if a String is empty ("") or null.
If your code:
if (StringUtils.isEmpty(requestBody.getStatus())) {
Assume we have two class:
#Data
class X {
private String field1;
}
#Data
class Y {
private String field2;
}
define static method
static <F, T>void copy(F f, T t, Function<F, String> get, BiConsumer<T, String> set){
String value = get.apply(f);
if(value != null && value.isEmpty()){
set.accept(t, value);
}
}
and use it in your code:
X x = new X();
Y y = new Y();
copy(x, y, X::getField1, Y::setField2);
You can implement this checking logic inside getter methods, i.e
public Optional<String> getChannelType() {
if (channelType.isEmpty() || channelType == null)
return Optional.empty();
else
return Optional.of(channelType);
}
If it's just copying between 2 beans with same variable names, then you can use BeanUtils.copyProperties to do so.
Here we can say the BeanUtil to copy non null values. So the code will be reduced to 1 lines.
BeanUtils.copyProperties(source, destination, (.. optional parameter to copy non null value)

System.identityHashCode is equal on String instances

because of reasons I am trying to copy/clone instances of objects. And in the case of String i tried something like this:
I do have an object like
class Foo{
private String test;
//Getters && Setters are generated
}
and a copy method like:
private static Object copyMemberData(Object originalMemberData) {
if (originalMemberData == null) {
return null;
}
...
if (originalMemberData instanceof String) {
return String.valueOf(originalMemberData);
}
...
}
which is used like
PropertyDescriptor propDesc = new PropertyDescriptor("test", Foo.class);
//Get Data from original object
final Object originalMemberData = propDesc.getReadMethod().invoke(originalFoo);
final Object copiedMemberData = copyMemberData(originalMemberData);
And afterwards I tried to compare the result with System.identityHashCode to ensure that I am not working on a reference.
if (System.identityHashCode(copiedMemberData) == System.identityHashCode(originalMemberData)) {
throw new RuntimeException("Cloning is buggy!");
}
And I am suprised this actually matches and throws me an error. Maybe someone can explain me the reason for that.
I found it out :-)
The String is the same even if I do compare it with == instead of equals. This is the case because the toString() method of the String.java class which is used in String.valueOf(Object obj) is implemented like:
public String toString() {
return this;
}
To successfully copy a String use:
return new String(((String)originalMemberData).toCharArray());

how to know if the map contains that object based on the object properties

I am using a map and want to use a value object as a map key..and a list as value. The value object has 2 properties first name, second name..i want to return map.containsKey() as true if both properties matched by some key in the same map..
I tried to use comparator as below
public class comaparatorEx implements Comparator<Test>{
public static void main(String args[]){
Map m= new HashMap<Test,List<String>>();
Test t = new Test();
t.setFirstname("vamsi");
t.setSecondname("priya");
List descriptionList=new ArrayList();
descriptionList.add("description1");
m.put(t, descriptionList);
Test t2 = new Test();
t2.setFirstname("vamsi");
t2.setSecondname("priya");
if(m.containsKey(t2)){
System.out.println("user found");
}
}
public int compare(Test o1, Test o2) {
if((o1.firstname.equals(o2.firstname) )&& o1.secondname.equals(o2.secondname))
return 0;
else return 1;
}
}
this is the value object i am using
public class Test {
String firstname;
String secondname;
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getSecondname() {
return secondname;
}
public void setSecondname(String secondname) {
this.secondname = secondname;
}
}
But it returns false for me..please help me ..thanks in advance
For a HashMap, you need to overwrite equals and hashCode in your class.
Possible implementation:
class Test
{
...
#Override
public int hashCode()
{
return 31*firstname.hashCode() + secondname.hashCode();
}
#Override
public boolean equals(Object obj)
{
// basic type validation
if (!(obj instanceof Test))
return false;
Test t = (Test)obj;
return firstname.equals(t.firstname) && secondname.equals(t.secondname);
}
}
Comparator is for comparison-based collections such as TreeMap. To use this, supply an instance of this class in the constructor:
Map m = new TreeMap<Test,List<String>>(new comaparatorEx());
But there is a problem with your compare function - there needs to be logical ordering between the elements (there isn't as you never return -1). String has a compareTo, which you can just use:
public int compare(Test o1, Test o2) {
int result = o1.firstname.compareTo(o2.firstname);
if (result == 0)
return o1.secondname.compareTo(o2.secondname));
else
return result;
}
HashMap uses the hashCode() and equals() methods, internally, to determine e.g. what buckets to look in, and whether the objects in that bucket are the same. You will need to implement both for your Test class, otherwise it will effectively default to reference equality (i.e. are they the exact same object)
You need override the hashcode() and equals() methods to give meaningful equality between the Test object.
HashMap insertions is bassed on the hashcode.
When we pass an both key and value to put() method to store on HashMap , it uses key object hashcode() method to calculate hashcode and they by applying hashing on that hashcode it identifies bucket location for storing value object and keys equals () method will be used to identify correct key value pair in HashMap .
Read more: http://javarevisited.blogspot.com/2011/02/how-hashmap-works-in-java.html#ixzz2fDozSqmi
you would have to override the default equals method in your test class.
you can write something like this.
#Override
public boolean equals(Object o) {
if(null != o && o instanceof test && o.attr1.equals(this.attr1)) return true;
else return false;
}
containskey In map looks at the equals method. More info in the java docs
The implementation of equals i have given is just an example. For a proper implementation you should read this

Categories