Get Object from Field - java

CLARIFICATION:
I do not know the objects name. That is where the problem comes in. I am creating an object like such:
`new Object(String attributes);
I am trying to run code in another class such as:
***.getStuff();
the trick to it is, there is no name for the Object. but i do know what String attributes is
The question: Is there any way to accomplish this without using the dreaded for loop?
This question is a bit tricky to word, but I will try my best. What I want to is get an object that matches a particular field without making a messy for loop. Something along the lines of:
Object A has the field String name.
String nameObj = "Tickle";
Object A has the name "Tickle"
if(nameObj.equals(Object A)){
//bla bla
}
Very confusing wording, yes. Sorry about that. I want to use Object A in my code without having to figure out which object it is, assuming all I have is its name. I am looking for a shortcut around using a for loop, I suppose.
Feel free to ask questions about what I am looking for. Sorry about the terribly worded question.
Poor coding, but this is what I am looking for...
nameObj.getName().getObjectA();

If you have a bunch of objects with names, and you want to grab an object by its name, I suggest you look up the class HashMap. HashMap lets you put in objects under keys, and when you give the hash map a key it returns the object associated with that key. So in your example, the keys would be string names.

Take at this implementation, that demonstrates what #Patashu said, create a map to the objects, in this case I just add an abstract class at the top of all.
import java.util.HashMap;
public class FindMeBaby {
public static void main(String[] args) {
Factory.add(new NiceGuy("first one"));
Factory.add(new FirstChild("ok im late"));
System.out.println(Factory.get("first one")
.getVeryImportantInformationThatOnlyThisClassKnows());
}
}
abstract class ParentOfAll {
protected String id;
public ParentOfAll(String id) {
this.id = id;
}
public String getId(){
return id;
}
public abstract String getVeryImportantInformationThatOnlyThisClassKnows();
}
class FirstChild extends ParentOfAll {
public FirstChild(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "this is a secret";
}
}
class NiceGuy extends ParentOfAll {
public NiceGuy(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "to say the true, i'm not that nice :)";
}
}
class Factory {
private static HashMap allTheObjects = new HashMap();
public static Object add(ParentOfAll object) {
allTheObjects.put(object.getId(), object);
return object;
}
public static ParentOfAll get(String key) {
return (ParentOfAll) allTheObjects.get(key);
}
}

This is another version, of the same implementation with a more transparent aproach, without the Factory class, the Parent itself will keep track of the instances and save in a list.
import java.util.HashMap;
public class FindMeBaby {
public static void main(String[] args) {
NiceGuy foo = new NiceGuy("first one");
FirstChild bar = new FirstChild("ok im late");
System.out.println(ParentOfAll.get("first one")
.getVeryImportantInformationThatOnlyThisClassKnows());
}
}
abstract class ParentOfAll {
protected String id;
public ParentOfAll(String id) {
this.id = id;
add(this);
}
public String getId() {
return id;
}
public abstract String getVeryImportantInformationThatOnlyThisClassKnows();
private static HashMap allTheObjects = new HashMap();
private static Object add(ParentOfAll object) {
allTheObjects.put(object.getId(), object);
return object;
}
public static ParentOfAll get(String key) {
return (ParentOfAll) allTheObjects.get(key);
}
}
class FirstChild extends ParentOfAll {
public FirstChild(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "this is a secret";
}
}
class NiceGuy extends ParentOfAll {
public NiceGuy(String id) {
super(id);
}
public String getVeryImportantInformationThatOnlyThisClassKnows() {
return "to say the true, i'm not that nice :)";
}
}

Related

downcast to subclass and get subclass only fields

I have classes similar to DataRequest & DataWithIdRequest. DataWithIdRequest gets passed into my controller method. I want to pass the subclass object ONLY to another class for processing. However, when I try to downcast to DataRequest the extra field is still showing. How can I accomplish this?
public class DataRequest {
private String name;
public String getName() {
return name;
}
public void setFirstName(String name) {
this.name = name;
}
}
public class DataWithIdRequest extends DataRequest {
private Integer id;
public Integer getId() {
return contractKey;
}
public void setContractKey(Integer id) {
this.id = id;
}
}
//controller
processData(request);
}
//domain class
public Boolean processData(DataRequest request) {
//request here has DataWithIdRequest field
//but I only want the subclass
}
public Boolean processData(DataRequest request) { }
Because in your method processData, request's type is DataRequest. You want it to be DataWithIdRequest.
public Boolean processData(DataWithIdRequestrequest request) { }
You can only offer a part of an API (application programmer's interface), by separating the code in an interface.
public interface Identified {
Integer getId();
public void setContractKey(Integer id);
}
public class DataWithIdRequest extends DataRequest implements Identified {
private Integer id;
#Override
public Integer getId() {
return contractKey;
}
#Override
public void setContractKey(Integer id) {
this.id = id;
}
}
public Boolean processData(DataRequest request) {
if (request instanceOf Identified identified) {
identified.setContractKey(13);
}
}
Or move the problem to the caller:
public Boolean processData(Identified request) {
request.setContractKey(13);
}
By the way it more usual to use int, boolean, the primitive types.
To hide the information completely, you need to create a new instance of DataRequest by DataWithIdRequest (that's why mapping library like mapstruct is useful), but not directly passing it.
Explanation:
This is how inheritance works, imagine a method takes a parameter of an interface or abstract class, by using instanceof inside the method we can check the object actual type and do something specific. e.g.
public void drawShape(Shape shape) {
if (shape instanceof Circle) {
Circle circle = (Circle) shape;
// do sth
} else if (shape instanceof Square) {
// do sth else
}
}
The above example is completely valid (although not a good programming style, that's another story).
The object inside the memory holds all the actual class details, passing it to a method doesn't change anything to the memory. The parameter (e.g. shape) is only another reference to the same memory location.
Maybe I don't understand the question fully but: as you want I it's not possible since:
public class DataWithIdRequest extends DataRequest
means DataRequest is a subset of DataWithIdRequest, it's an intersection.
You unfortunately need to find an other way

How to pass multiple Types that implement the same interface?

Firstly apologies about the not so great title, I am new to Java and wasn't sure how to title this.
I have a interface class "TestInterface":
ublic interface TestInterface {
String getForename();
void setForename(String forename);
String getSurname();
void setSurname(String surname);
}
"TestImpl" implements "TestInterface":
public class TestImpl implements TestInterface{
private String forename;
private String surname;
#Override
public String getForename() {
return forename;
}
public void setForename(String forename) {
this.forename = forename;
}
#Override
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
}
Then I have a call called "ExtendTest" which extends "TestImpl":
public class ExtendTest extends TestImpl{
private String firstLineAddress;
public String getFirstLineAddress() {
return firstLineAddress;
}
public void setFirstLineAddress(String firstLineAddress) {
this.firstLineAddress = firstLineAddress;
}
}
I then have this "Entity" class:
import java.util.List;
public class Entity {
private List<TestInterface> testInterfaces;
private List<ExtendTest> extendTests;
public List<TestInterface> getTestInterfaces() {
return testInterfaces;
}
public void setTestInterfaces(List<TestInterface> testInterfaces) {
this.testInterfaces = testInterfaces;
}
public List<ExtendTest> getExtendTests() {
return extendTests;
}
public void setExtendTests(List<ExtendTest> extendTests) {
this.extendTests = extendTests;
}
}
and finally this "DoStuff" class where the dostuff method accepts a parameter of type List
import java.util.List;
public class DoStuff {
public void doStuff(List<TestInterface> testData) {
}
}
I try to test this like so:
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
DoStuff doStuff = new DoStuff();
Entity entity = new Entity();
// Works
doStuff.doStuff(entity.getTestInterfaces());
// Does not work
doStuff.doStuff(entity.getExtendTests());
}
}
However where the comment is "Does not work" their is an error
Required type:
List<TestInterface>
Provided:
List<ExtendTest>
My question is how do I make it so that I can pass it in. My understanding was that becase they all implement TestInterface that it would work but I think I am wrong with this.
Thanks for any help and learnings here :)
You've run afoul of PECS. I recommend reading the linked answer for a more detailed explanation, but here's the bits specific to your use case.
When you have a generic type (List, in your case), if you only read from it, you should write List<? extends MyInterface>. If you only write to it, you should write List<? super MyInterface>. If you do both, then you want List<MyInterface>. Why do we do this? Well, look at your code.
public void doStuff(List<TestInterface> testData) { ... }
This function takes a List<TestInterface>. The List interface has a ton of capability. You can add and remove things to it in addition to just reading from it. And doStuff expects a list of TestInterface. So it's entirely fair game for the implementation of doStuff to do
testData.add(new ClassIJustMadeUp());
assuming ClassIJustMadeUp implements TestInterface. So we definitely can't pass this function a List<ExtendTest>, since that list type can't contain ClassIJustMadeUp.
However, if your function does only read from the list and isn't planning to add anything to it, you can write the signature as
public void doStuff(List<? extends TestInterface> testData) { ... }
and now you can pass a List of any type which extends TestInterface. It's fine to read from this list, since any type which extends TestInterface clearly can be upcast safely to TestInterface. But if we try to add a list element, that's a compiler error since the list doesn't necessarily support that particular type.

I want to make universal method in CLASS for all enums

public class TableContent {
public static String EXCEL_SHEET_NAME = Nit.THEAD.getName();
public static String FILENAME= Nit.FILENAME.getName();
public enum Nit {
FILENAME("Nit-workorder-list"),
THEAD("NIT WORKORDER"),
TENDERSPECNO("TENDER SPECFICATION NO."),
FEE("TENDER FEE"),
SDAMOUNT("SD AMOUNT"),
TYPE("NIT TYPE"),
PRE_BID("PRE BIDDING DATE"),
OPEN_DATE("OPENING DATE"),
STATUS("CONTRACTOR STATUS");
private final String name;
public String getName() {
return name;
}
private Nit(String name) {
this.name = name;
}
public static Nit getNitHeadByName(String name)
{
Nit[] nit=Nit.values();
if(nit==null)
{
return null;
}
for(Nit nitHead:nit)
{
if(nitHead.getName().equals(name))
return nitHead;
}
return null;
}
public enum NitWorkOrder {
}
public enum NitList {
}
My objective is:
I want to export excel sheet from my application, every time I need to hardcode the table headings, which was not good programming practice.
So I use enum to overcome the hardcode problem. Now there are different table heading according to the list, then I enclosed all the required ENUMS in single class.
I used to write getXXXByName() and getXXXByValue() to access the enum, by name or by value.
But he problem is I need to write getXXXByName() and getXXXByValue() everytime inside each enum. I want to write these methods inside the class and outside the enums, and access those methods with the help of class name.
I just want to declare my constants inside enum.
Please kindly suggest me an idea or a way so I can make this method universal which will work for each and every enum. I want to write these methods in such a way so it can be accessed for all enums enclosed in my class. I thought about generics but I have little knowledge.
You can use generics to push functionality up to a parent class by telling the parent class that the type is an enum that implements an interface.
// Use an interface to inform the super class what the enums can do.
public interface Named {
public String getName();
}
// Super class of all Tables.
public static class Table<E extends Enum<E> & Named> {
private final Class<E> itsClass;
private final String sheetName;
private final String fileName;
public Table(Class<E> itsClass) {
this.itsClass = itsClass;
// Walk the enum to get filename and sheet name.
String sheetName = null;
String fileName = null;
for ( E e: itsClass.getEnumConstants() ){
if ( e.name().equals("FILENAME")) {
fileName = e.getName();
}
if ( e.name().equals("THEAD")) {
sheetName = e.getName();
}
}
this.sheetName = sheetName;
this.fileName = fileName;
}
// Use the interface and the enum details to do your stuff.
public E getByName (String name) {
for ( E e: itsClass.getEnumConstants() ){
if ( e.getName().equals(name)) {
return e;
}
}
return null;
}
}
// Extend Table and tell it about your enum using the super constructor.
public static class TableContent extends Table<TableContent.Nit> {
public TableContent() {
super(TableContent.Nit.class);
}
public enum Nit implements Named{
FILENAME("Nit-workorder-list"),
THEAD("NIT WORKORDER"),
TENDERSPECNO("TENDER SPECFICATION NO."),
FEE("TENDER FEE"),
SDAMOUNT("SD AMOUNT"),
TYPE("NIT TYPE"),
PRE_BID("PRE BIDDING DATE"),
OPEN_DATE("OPENING DATE"),
STATUS("CONTRACTOR STATUS");
private final String name;
Nit(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}

Trying to store Bukkit ItemStack field to a file but ItemStack is not Serrializable

ItemStack is not serializable and I'm trying to save an object called Objective with an ItemStack field to a file but since ItemStack is not serializable this does not work. I tried extending ItemStack and implementing Serializable and changing the field to my new serializable sub class but this also did not work. Here are the relevant parts of my original code:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import org.bukkit.inventory.ItemStack;
public class Objective implements Serializable {
private static final long serialVersionUID = -2018456670240873538L;
private static ArrayList<Requirement> requirements = new ArrayList<>();
private String name;
private Requirement requirement;
private ItemStack reward;
private int tillComplete;
private boolean complete;
public Objective(String name, int requirementIndex, int tillComplete, ItemStack reward) {
if(requirements.isEmpty()) {
requirements.add(Requirement.kill_Skeletons);
requirements.add(Requirement.kill_Spiders);
requirements.add(Requirement.kill_Zombies);
}
this.name = name;
this.requirement = requirements.get(requirementIndex);
this.tillComplete = tillComplete;
this.reward = reward;
complete = false;
}
public String getName() {
return name;
}
public Object getRequirement() {
return requirement;
}
public static ArrayList<Requirement> getRequirements() {
return requirements;
}
public static void setRequirements(ArrayList<Requirement> requirements) {
Objective.requirements = requirements;
}
public int getTillComplete() {
return tillComplete;
}
public void setTillComplete(int tillComplete) {
this.tillComplete = tillComplete;
}
public void setName(String name) {
this.name = name;
}
public void setRequirement(Requirement requirement) {
this.requirement = requirement;
}
public void setReward(ItemStackSerializable reward) {
this.reward = reward;
}
public void setComplete(boolean complete) {
this.complete = complete;
}
public ItemStack getReward() {
return reward;
}
public boolean isComplete() {
return complete;
}
}
Elsewhere in my code this line of code:
ItemStack reward = new ItemStack(Material.DIAMOND_SWORD);
Objective objective = new Objective(args[1] ,Integer.parseInt(args[2]), Integer.parseInt(args[3]), reward);
is giving me this error:
java.io.NotSerializableException: org.bukkit.inventory.ItemStack
How can I serialize this object? I need to store it but Java wont let me. Thanks for your help. If you need anymore code snippets or other information please let me know.
This is most likely an XY problem. ItemStack is not serializable, as it represents an actual stack of items at runtime. This would not make sense to store in a file. It might be worth looking at the ConfigurationSerializable interface, which is implemented by ItemStack, but I don't think you need that here.
In your example, the ItemStack that you are trying to serialize doesn't have any metadata. It is a single diamond sword. If all your rewards are just a single item, all you need to save is the Material and you can create a new ItemStack from that Material every time you want to give a player a reward. Since Material is an enum, it is serializable by default.
You could also serialize an int for stack size if some of your rewards require a stack of multiple items. If you need any metadata, serialize the data needed to construct that at runtime. For example, to give an item lore, you would store a List<String> (with a serializable implementation of List).

Safe alternative to calling of abstract method from constructor

I know it's a bad idea, and it causes bugs. The problem is, I need the "intended" behavior.
"Low":
// simplified example
abstract class Low {
String name;
public Low(String name) {
this.name = name;
}
public Low(int id) {
this.name = getNameForId(id);
}
public Low() {} // will be loaded later
#Override
public String toString()
{
return name;
}
public void load(InputStream in) {
// --- grab ID from stream ---
this.name = getNameForId(id);
}
protected abstract String getNameForId(int id);
}
And "High":
class High extends Low {
public High(int id) { super(id); }
public High(String name) { super(name); }
public High() {} // will be loaded later
#Override
protected String getNameForId(int id)
{
return Registry.getName(id);
}
}
Note that in this particular case, it will work just fine. But it will fall apart once the overriding method needs to use some field.
How to do this better?
You want to separate out loading a name for an ID from your Low and High objects. Introduce an interface for loading names given an ID.
public interface NameProvider
{
String getNameForId(String id);
}
Add specific implementations for each source of names.
public class InputStreamNameProvider implements NameProvider
{
private InputStream inputStream;
// Constructor
public String getNameForId(String id)
{
// return name loaded via inputStream
}
}
public class RegistryNameProvider implements NameProvider
{
public String getNameForId(String id)
{
return Registry.getName(id);
}
}
You could then add a new constructor to Low that takes the NameProvider and String id as arguments
public Low(NameProvider provider, String id)
{
this(provider.getNameForId(id));
}
or even use the name provider before constructing the instance of Low or High. The main idea is the separation of loading the name for an ID from the Low and High objects.
You can avoid calling the abstract method by adding a public void load(int id) method (like you do for InputStream) and removing the Constructor(int id).
You might want to add some Factory functionality to ensure your constructed instance is can never be accessed without having a proper name value.

Categories

Resources