How to retrieve class instance using one attribute - java

I have a class Item, with each item there is a unique identifier which is associated with it. Is it feasible to retrieve the entire Item instance based on the unique identifier. That is, I want to use the unique identifier as the key.
class Item{
int id;
String name;
Date d;
}
Now based on id, I want to retrieve its name and date. Is there some way to do so?
First I store the class instance..using a constructor, now based on some previously stored instance, given id. I want to retrieve the entire instance

You could make a HashMap like this.
HashMap<Integer, Item> itemMap = new HashMap<Integer, Item>();
And just do something like,
itemMap.put(itemInstance.id, itemInstance);
Or maybe even an ArrayList<Item> and create a getter method that loops through the ArrayList for that specific id.
In any case, you're going to have create some type of collection.

I think you are confusing a class instance with a container that searches for a class instances.
Strictly speaking, there is nothing about the class's id which will help you find that class instance. However, in a collection of class instances, you could simply iterate the objects, checking each one's id. All of this is completely dependent on your collection's type.

First I store the class instance..using a constructor, now based on some previously stored instance, given id. I want to retrieve the entire instance
There is no intrinsic support for this in Java.
You could implement it yourself something like this:
public class Item {
private static HashMap<Integer, Item> all = new HashMap<Integer, Item>();
private final int id;
private String name;
private Datedate;
public Item(int id, String name, Date date) {
this.id = id; this.name = name; this.date = date;
synchronized (all) {
all.put(id, this);
}
}
// getters and setters
public static getInstance(int id) {
synchronized (all) {
return all.get(id);
}
}
}
HOWEVER ... this is a massive storage leak. Every Item instance ever created is always reachable via the all static, and therefore cannot be garbage collected. In a lot of cases, this is enough to make this approach non-viable.

Related

Diff two classes fields names and structure

My task
Force two classes to have the same (or similar) field names (and their types)
Description
I have an entity and Data Transfer Objects (DTO).
How do I force that if someone adds / removes / changes a field in entity, a test will fail, so DTO class matches the entity class by fields names and if possible by fields structure.
class City {
private String name;
private CityDetails cityDetails;
private Mayor mayor;
}
class Mayor {
private String name;
private LocalDate electionFrom;
private LocalDate electionTo;
}
class CityDto {
private String name;
private CityDetailsDto cityDetails;
private MayorDto mayor;
}
class MayorDto {
private String name;
// The client of the end-point of such DTO does not care about the mayor election.
}
CityDetails and CityDetailsDto can be different or not necessary. I would like to have their diff.
Approaches
Using so called diff tool
Let's imagine a diff tool which has input parameters - two objects and output parameter - Map, where Diff is a structure oldValue, newValue. This tool returns difference between input arguments.
public Map<String, Diff> diff(final Object first, final Object second) {
// This is implemented.
return innerDiff(first, second, otherParameters); //
}
public class Diff {
private String oldValue;
private String newValue;
// getters, setters, constructor.
}
// To achieve this, we used Guava Plain map. It works well!
How do I achieve the same for classes. I want to diff two classes and have their fields as difference.
public Map<String, FieldDiff> diff(Class<?> type1, Class<?> type2) {
// How?
}
One idea is to use reflection and iterate though all fields of the class.
How about using toString and compare?
As an alternative, we define toString() methods in both and then compare.
How to do that if some fields are missing?
Serialize into JSON
Similar to the previous one, but serializing both objects into JSON and then compare their classes by json field names. However, if our entity have already annotation DoNotSerializeNulls with is equal to #JsonInclude(JsonInclude.Include.NON_NULL) #JsonIgnoreProperties(ignoreUnknown = true), then how to do that?
References
https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application

How to use the getter method which is stored in mongodb for some other POJO class?

I am having one class which is having getter and setter methods i am storing that getter method in mongodb with some other collection. After getting the method name from DB how to access that method. Whether it is possible to do like this or not?
public class MappingAlgorithmScoreGenerationRules {
#Field(value = FieldNames.CATEGORY)
private String category;
#Field(value = FieldNames.ATTRIBUTE_NAME)
private MappingScoreGenerationLogic attributeName;
#Field(value = FieldNames.PRIORITY)
private Integer priority;
#Field(value = FieldNames.ATTRIBUTE_SCORE)
private Integer attributeScore;
#Field(value = FieldNames.FINAL_THRESHOLD)
private Integer finalThreshold;
#Field(value = FieldNames.RESULT_COUNT)
private Integer resultCount;
#Field(value = FieldNames.NORMALIZED_VALUE)
private Integer normalizedValue;
#Field(value = FieldNames.GETTER_METHOD)
private String getterMethod;
}
This is the class where i am storing the method name.
public class MatchEntry {
private double matchedWeight;
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
getMatchedWeight is the method name i am going to store in the DB MappingAlgorithmScoreGenerationRules.
After getting the method name how to access the method name?
I want to access like
For example: MatchEntry.(the value get from db)
Use reflection API - https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html
Method methodToInvoke
= MatchEntry.class.getMethod("methodName", methodParams,..);
methodToInvoke.invoke(matchEntryInstance, params,..);
In Java you can achieve method access by name using reflection (https://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html).
This is a tutorial you may be able to use to lean more about this language feature: https://www.geeksforgeeks.org/reflection-in-java/
In your example, let's say you have loaded an instance of MappingAlgorithmScoreGenerationRules from the database, whose getterMethod attribute returns "getMatchedWeight".
Let's also assume that you have an instance of MatchEntry.
You would then access as follows:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String getterMethodName = rules.getGetterMethod();
Method getter = MatchEntry.class.getMethod(getterMethodName);
Object value = getter.invoke(entry);
This code snippet omits Exceptions, in particular NoSuchMethodException and InvocationTargetException.
Please note that if you choose this approach, and depending heavily on the rest of your domain model, you will also need to be very careful with assumptions about the return type of the actual value (unless you can somehow guarantee that they are all the same, in which case you could cast the value).
Code that uses reflection is also inherently brittle and prone to failure as soon as you refactor. Imagine you have a populated database with these rules, and during a code review a couple of methods are renamed. Inoccuous change? Or will your entire setup break on the next deploy?
A (type-)safer approach might be to ensure all entries and related objects derive from an interface that standardises the return type on a getValue(String attributeName) method, so instead of messing with reflection you might do:
MappingAlgorithmScoreGenerationRules rules = ....; //load from DB
MatchEntry entry = ...; //wherever it comes from
String attributeName = rules.getAttribute(); //instead of 'getterMethod'
Object value = entry.getValue(attributeName);
where MatchEntry.getValue might be defined as:
public Object getValue(String attribute) {
switch(attribute) {
case "matchedWeight": return getMatchedWeight();
default: return null; //or you could throw an exception
}
}
This would easily survive any kind of method name refactoring and reorganisation, but adds the overhead of adding a case to the switch for every new attribute.
This problem could be partially solved with a runtime annotation that essentially binds an attribute name to a getter method, e.g.:
public class MatchEntry implements Matchable {
private double matchedWeight;
#MyCustomAnnotation("matchedWeight")
public double getMatchedWeight() {
return matchedWeight;
}
public void setMatchedWeight(double matchedWeight) {
this.matchedWeight = matchedWeight;
}
}
public interface Matchable {
default Object getValue(String attributeName) {
//read methods annotated with 'MyCustomAnnotation's in current class and call the one with matching value
}
}
Your getValue(String attributeName) would be tasked with reading these annotations and dynamically figuring out which getter to call. Still requires the annotation to be added everywhere it's needed, but at least it's with the getter and not hidden in some switch that's potentially duplicated across multiple class definitions.
Instead you just need a single default definition in the parent interface, as hinted above.

add softly linked attribute spring-data-rest?

I have just a straight forward question.
Just imagine I have an entity class which is mapped to a table with columns. I just need to introduced a new attribute to the same class, whose value needs to be fetch from a column in another table (What I mean by softly linked).
I know this is not quite a clean requirement.
Anyway, is it possible?
Not sure if this is what you're looking for, but here - you can possibly extend the entity.
Say your entity class is Drink
class Drink {
String weight;
String size;
//other getter setter constructor etc
}
And then you have a service from which you are able to fetch a value from a column:
class FlavorService {
static String getFlavor(){ /*can be static since it's only retrieval/idempotent*/ };
}
So now what you can do is create an extended class
class FlavoredDrink extends Drink{
String flavor;
public FlavoredDrink (String weight, String size){
super(weight, size);
this.flavor = FlavorService.getFlavor();
}
}
Then you just have to use FlavoredDrink.

How can we get immutable object if class did not implement cloneable

I have few issues/doubts to fill values in a HashMap
I want a HashMap to accept "Student" as key and "Details" as value.
Since key to a hashMap should be immutable I have some doubts how can this be dealt if
Student class did not cloneable
Student class has reference to which in turn have reference to "Lab"
public class Student {
private String id;
private String name;
private Department dept;
public Student(String id, String name, Department dept)
{
this.id=id;
this.name=name;
this.dept=dept;
}
public Department getDepartment()
{
return this.dept;
}
}
public class Department {
private String deptId;
private Lab lab;
public Department(String deptId, Lab lab)
{
this.deptId=deptId;
this.lab=lab;
}
public void setLab(Lab lab)
{
this.lab=lab;
}
}
public class Lab {
private String labId;
private String labName;
public Lab(String labId, String labName)
{
this.labId=labId;
this.labName=labName;
}
}
public class StudentDetails
{
private String fatherName;
private String address
public StudentDetails(String fatherName, String address)
{
this.fatherName=fatherName;
this.address=address;
}
}
public class StudentMaintainer {
public static void main(String[] args)
{
StudentDetails stDetails= new StudentDetails("John","Mumbai");
Lab lab= new Lab("100","CS");
Department dept= new Department("900", lab);
Student st = new Student("3000",dept);
Map<Student,StudentDetails> studentMaintainer= new ArrayList<>();
studentMaintainer.put(st,stDetails);
}
}
Now Even if Student is cloneable, I can get reference of Department and call setLab() which changes the StudentObject. (Am I wrong?)
Now if Department and Lab are from 3rd party jars, how can I use Student Object in my Map if Student hashCode is (primeNumber+Student.id+Department.id+Lab.id).hashcode() [just some weird case];
Immutability has nothing to do with Cloneable as far as I understand it, and in fact just the opposite. Immutability has more to do with declaring the class final and using immutable fields, non-overridable methods, no setter methods, getter methods that return deep copies of fields or immutable fields, etc... Please read A Strategy for Defining Immutable Objects for more on this.
Also your code has a pseudo-constructor:
public void Student(String id, String name, Department dept)
{
this.id=id;
this.name=name;
this.dept=dept;
}
A true constructor should not be declared to return anything, not even void. Better would be:
// note the difference?
public Student(String id, String name, Department dept)
{
this.id=id;
this.name=name;
this.dept=dept;
}
Also, your Student class should properly override equals and hashCode if it is to work well as a key for a HashMap.
Now Even if Student is cloneable, I can get reference of Department
and call setLab() which changes the StudentObject. (Am I wrong?)
You are correct. This can happen, and can cause your Student class to appear to be mutated. For an instance of Student to be immutable, you must not be able to modify any of its fields[0]. That includes calling something like a setter method on one of its fields.
Now if Department and Lab are from 3rd party jars, how can I use
Student Object in my Map if Student hashCode is
(primeNumber+Student.id+Department.id+Lab.id).hashcode() [just some
weird case];
That is a very good question. You obviously can't just change the classes to be immutable, since you don't have control over them, so you may have to get a bit creative. Possible solutions:
if the third party objects you want to use are interfaces, you could implement the interface with your own type, where the body of every mutator method throws an exception (think e.g. java.util.Collections.unmodfiableList). This has the benefits that you can still refer to the third party class in your codebase, but the drawback that calling mutator methods will fail at runtime, rather than at compile time.
write adapters in your own codebase, like this:
public final class MyImmutableDepartment {
private final MyImmutableLab lab;
private final String departmentId;
public MyImmutableDepartment(Department thirdPartyMutableDepartment) {
this.departmentId = thirdPartyMutableDepartment.getId();
this.lab = new MyImmutableLab(thirdPartyMutableDepartment.getLab());
}
// getters and the MyImmutableLab class left as an exercise
}
This has the advantage that you know at compile time, the classes cannot be mutated.
The downside in both approaches is that you basically have to mirror every class from the third party library, to ensure they're immutable.
I don't think there's any other alternatives.
[0] there are some cases where this is possible, and can be used for internal caching, but it's a decent guideline to stick to when learning.
Student does not need to be immutable! Specifically, the requirement is that the behavior of equals/hashCode doesn't change when the key is in the HashMap.
This can be accomplished in three ways:
Don't implement equals/hashCode. If you use the default reference equality, it doesn't matter how you mutate the key. To clarify intent, override those methods, explicitly call super.equals, and make them final.
Don't include any fields that will mutate in your calculation of equals/hashCode. Or, if the properties of a field may change but not the reference, use reference equality (==) instead of field.equals() and call System.identityHashCode(field) instead of field.hashCode()
Don't mutate the object while it is used as a key in the HashMap. A bit dangerous, but works fine if references aren't held by code beyond your control. Document the requirement.
But, in your concrete example, each student has an id. Why would you use any other properties when implementing equals/hashCode.?

What would be the best way to implement a constant object?

First of all I should probably say that the term 'constant object' is probably not quite right and might already mean something completely different from what I am thinking of, but it is the best term I can think of to describe what I am talking about.
So basically I am designing an application and I have come across something that seems like there is probably an existing design pattern for but I don't know what it is or what to search for, so I am going to describe what it is I am trying to do and I am looking for suggestions as to the best way to implement it.
Lets say you have a class:
public class MyClass {
private String name;
private String description;
private int value;
public MyClass(String name, String description, int value) {
this.name = name;
this.description = description;
this.value = value;
}
// And I guess some getters and setters here.
}
Now lets say that you know in advance that there will only ever be say 3 instances of this class, and the data is also known in advance (or at least will be read from a file at runtime, and the exact filename is known in advance). Basically what I am getting at is that the data is not going to be changed during runtime (once it has been set).
At first I thought that I should declare some static constants somewhere, e.g.
public static final String INSTANCE_1_DATA_FILE = "path/to/instance1/file";
public static final String INSTANCE_2_DATA_FILE = "path/to/instance2/file";
public static final String INSTANCE_3_DATA_FILE = "path/to/instance3/file";
public static final MyClass INSTANCE_1 = new MyClass(getNameFromFile(INSTANCE_1_DATA_FILE), getDescriptionFromFile(INSTANCE_1_DATA_FILE), getValueFromFile(INSTANCE_1_DATA_FILE));
public static final MyClass INSTANCE_2 = new MyClass(getNameFromFile(INSTANCE_2_DATA_FILE), getDescriptionFromFile(INSTANCE_2_DATA_FILE), getValueFromFile(INSTANCE_2_DATA_FILE));
public static final MyClass INSTANCE_3 = new MyClass(getNameFromFile(INSTANCE_3_DATA_FILE), getDescriptionFromFile(INSTANCE_3_DATA_FILE), getValueFromFile(INSTANCE_3_DATA_FILE));
Obvisouly now, whenever I want to use one of the 3 instances I can just refer directly to the constants.
But I started thinking that there might be a cleaner way to handle this and the next thing I thought about was doing something like:
public MyClassInstance1 extends MyClass {
private static final String FILE_NAME = "path/to/instance1/file";
public String getName() {
if (name == null) {
name = getNameFromFile(FILE_NAME);
}
return name;
}
// etc.
}
Now whenever I want to use the instances of MyClass I can just use the one I want e.g.
private MyClass myInstance = new MyClassInstance2();
Or probably even better would be to make them singletons and just do:
private MyClass myInstance = MyClassInstance3.getInstance();
But I can't help but think that this is also not the right way to handle this situation. Am I overthinking the problem? Should I just have a switch statement somewhere e.g.
public class MyClass {
public enum Instance { ONE, TWO, THREE }
public static String getName(Instance instance) {
switch(instance) {
case ONE:
return getNameFromFile(INSTANCE_1_DATA_FILE);
break;
case TWO:
etc.
}
}
}
Can anyone tell me the best way to implement this? Note that I have written the sample code in Java because that is my strongest language, but I will probably be implementing the application in C++, so at the moment I am more looking for language independent design patterns (or just for someone to tell me to go with one of the simple solutions I have already mentioned).
If you want the values to be constant, then you will not need setters, otherwise code can simply change the values in your constants, making them not very constant. In C++, you can just declare the instances const, although I'd still get rid of the setters, since someone could always cast away the const.
The pattern looks ok, although the fact that you are creating a new instance each time one is requested, is not usual for constants.
In java, you can create enums that are "smart" e.g.
public enum MyClass {
ONE(INSTANCE_1_DATA_FILE),
TWO(INSTANCE_2_DATA_FILE),
//etc...
private MyClass(String dataFile)
{
this(getNameFromDataFile(dataFile), other values...)
}
private MyClass(String name, String data, etc...)
{
this.name = name;
// etc..
}
public String getName()
{
return name;
}
}
In C++, you would create your MyClass, with a private constructor that takes the filename and whatever else it needs to initialize, and create static const members in MyClass for each instance, with the values assigned a new instance of MyClass created using the private constructor.
EDIT: But now I see the scenario I don't think this is a good idea having static values. If the types of ActivityLevel are fundamental to your application, then you can enumerate the different type of activity level as constants, e.g. a java or string enum, but they are just placeholders. The actual ActivityDescription instances should come from a data access layer or provider of some kind.
e.g.
enum ActivityLevel { LOW, MED, HIGH }
class ActivityDescription
{
String name;
String otherDetails;
String description; // etc..
// perhaps also
// ActivityLevel activityLevel;
// constructor and getters
// this is an immutable value object
}
interface ActivityDescriptionProvider
{
ActivityDescription getDescription(ActivityLevel activityLevel);
}
You can implement the provider using statics if you want, or an enum of ActivityDescription instnaces, or better still a Map of ActivityLevel to ActivityDescription that you load from a file, fetch from spring config etc. The main point is that using an interface to fetch the actual description for a given ActivityLevel decouples your application code from the mechanics of how those descriptions are produced in the system. It also makes it possible to mock the implementation of the interface when testing the UI. You can stress the UI with a mock implementation in ways that is not possible with a fixed static data set.
Now lets say that you know in advance that there will only ever be say 3 instances of this class, and the data is also known in advance (or at least will be read from a file at runtime, and the exact filename is known in advance). Basically what I am getting at is that the data is not going to be changed during runtime (once it has been set).
I'd use an enum. And then rather in this flavor:
public enum MyEnum {
ONE("path/to/instance1/file"),
TWO("path/to/instance2/file"),
THREE("path/to/instance3/file");
private String name;
private MyEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Which can be used as follows:
MyEnum one = MyEnum.ONE;
String name = one.getName();
(I'm too slow once again, you already accepted an answer, but here it is anyway...)
You want to (a) prevent changes to the data held in objects of MyClass, and (b) allow only a fixed set of MyClass objects to exist, implying that runtime code should not be able to create new instances of MyClass.
Your initial example has a public constructor, which violates (b)
I'd use a Factory approach so the Factory is the only thing that can create instances, and the class doesn't provide any setters so it's immutable.
Depending on how much flexibility you want for the future, you could put the factory and the class in the same package and limit scope that way, or you could make MyClass an inner class within the factory. You may also consider making MyClass an interface separate from its implementation.
A properties file could be used to configure the factory itself.
The properties file (e.g. "foo.properties") could look something like
one=/path/to/datafile1
two=/another/path/to/datafile2
three=/path/to/datafile3
I use "Foo" instead of "MyClass" in the (Java) examples below.
public class FooFactory
{
/** A place to hold the only existing instances of the class */
private final Map<String, Foo> instances = new HashMap<String, Foo>();
/** Creates a factory to manufacture Foo objects */
// I'm using 'configFile' as the name of a properties file,
// but this could use a Properties object, or a File object.
public FooFactory(String configfile)
{
Properties p = new Properties();
InputStream in = this.getClass().getResourceAsStream();
p.load(in); // ignoring the fact that IOExceptions can be thrown
// Create all the objects as specified in the factory properties
for (String key : p.keys())
{
String datafile = p.getProperty(key);
Foo obj = new Foo(datafile);
instances.put(key, obj);
}
}
public Foo getFoo(String which)
{
return instances.get(which);
}
/** The objects handed out by the factory - your "MyClass" */
public class Foo
{
private String name;
private String description;
private int value;
private Foo(String datafile)
{
// read the datafile to set name, description, and value
}
}
}
You're set to allow only your predefined instances, which can't be changed at runtime, but you can set it all up differently for another run at a later time.
Your first method seems to me like the best and the least prone to code rot. I'm not impressed by the idea of subclassing an object just to change the file name that contains the data that will be used to build it.
Of course, you could maybe improve on your original idea by wrapping these all in an outer class that provides some sort of enumeration access. A collection of MyClass's in other words. But I think you should discard this subclassing idea.
First, you really should be limiting where you use these instances in the code. Use them in as few places as possible. Given these are file names, I expect you want three class instances which accesses the files. How many classes are required depends on what your want to do with them? Look at the Singleton pattern for these classes.
Now you don't need the constants, but could have a helper class which will read the file containing the file names and supply them to the reader class. The code to find then name could also be a method called by the static initializer of the Singleton.
The common approach is to use a map:
private static final Map<String, YouClass> mapIt =
new HashMap<String, YouClass>(){{
put("one", new YourClass("/name", "desc", 1 )),
put("two", new YourClass("/name/two", "desc2", 2 )),
put("three", new YourClass("/name/three", "desc", 3 ))
}}
public static YourClass getInstance( String named ) {
return mapIt.get( named );
}
Next time you need it:
YouClass toUse = YourClass.getInstance("one");
Probably using strings as keys is not the best option but you get the idea.

Categories