downcast to subclass and get subclass only fields - java

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

Related

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.

Builder pattern vs encapsulation of a data

How should I retain Encapsulation Principle of OOP, when using builder pattern? I mean fact that builder should provide abstraction layer between object and the code that uses it, so that it can be constructed part-by-part, requires either making setter for every parameter of an object that we would normally pass in the constructor. That again may be undesirable in some cases, as I don't want client to be able to modify value that I have to via builder. Example to picture what I mean is below:
public class Cat
{
private string _race;
private string _name;
public Cat()
{
_race = "common";
_name = string.Empty;
}
public void setRace(string race) { _race = race; }
public void setName(string name) { _name = name; }
}
public class CatBuilder
{
private Cat _objectUnderConstruction;
public CatBuilder() { _objectUnderConstruction = new Cat(); }
public CatBuilder WithName(string name)
{
_objectUnderConstruction.setName(name);
return this;
}
public CatBuilder OfRace(string race)
{
_objectUnderConstruction.setRace(race);
return this;
}
}
This is not production code, I wrote it now with presentation in mind, so do not get mad on how it is constructed.
In the example above there is need to set cat's race, as we need that information for the purpose of object filling, so we need to pass info into it. At the same time I don't want anyone to ever change race of my cat during its lifetime (e.g. it would change from egyptian to british in the middle of processing) Normally I would get rid of accessor method, but I need for the builder. This way, encapsulation of data is hurt (because straight get and set aren't encapsulating anything), and I want to avoid it.
This example is simple and I could pass parameter in constructor, but imagine bigger class, where there is a lot of such fields, what in this case? Should I pass some configuration object inside (which is almost like builder, but simpler, hence builder is pointless) or pass the builder itself to the constructor (which is weird, but what do I know)?
How I should do that?
If your builder is tightly-coupled with your class you can make Builder subclass of the object being constructed:
public class Cat
{
private string _race;
private string _name;
public Cat()
{
_race = "common";
_name = string.Empty;
}
private void setRace(string race) { _race = race; }
private void setName(string name) { _name = name; }
public class Builder
{
private Cat _objectUnderConstruction;
public CatBuilder() { _objectUnderConstruction = new Cat(); }
public CatBuilder WithName(string name)
{
_objectUnderConstruction.setName(name);
return this;
}
public CatBuilder OfRace(string race)
{
_objectUnderConstruction.setRace(race);
return this;
}
}
}
This way, you'll be able in Builder to access private fields and methods of Cat and use it like new Cat.Builder().OfRace("").OfName("").Build().

Could I pass annotation to child class which extends it?

I'm lazy person... i just want the simplest way, now i'm learning android room. This might be answered here "Why is it not possible to extend annotations in Java?", but it seems like to try pass annotation to another annotation, right? So, Could i pass annotation to the child class for example, here is my parent class 'Model':
#Entity
public abstract class Model implements Parcelable{
#Nullable
#PrimaryKey
private Object id;
public String toJSON(){
return new Gson().toJson(this);
}
public <T> T getId(Class<T>type) {
if(type.equals(Integer.class)||type.equals(int.class)) {
return (T) Integer.valueOf(new Double(Double.parseDouble(String.valueOf(id))).intValue());
}
else if(type.equals(Long.class)||type.equals(long.class)) {
return (T) Long.valueOf(new Double(Double.parseDouble(String.valueOf(id))).longValue());
}
else if(type.equals(Double.class)||type.equals(double.class)) {
return (T) Double.valueOf(id.toString());
}else if(type.equals(UUID.class)){
return (T) UUID.fromString(String.valueOf(id));
}
return type.cast(id);
}
public <T> void setId(T id) {
this.id = id;
}
}
I tried to pass #Entity to child class.
public class Movie extends Model {
public static final String IDENTIFIER = Movie.class.getSimpleName();
#SerializedName("popularity")
private double popularity;
#SerializedName("vote_count")
private long voteCount;
#SerializedName("video")
private boolean video;
}
Because my data access object cannot detect my 'Movie' class, except i'm added Entity annotation
#Dao
public interface FavMovieDAO {
#Query("SELECT * FROM Movie WHERE id = :movieId")
public Movie find (int movieId);
}
If there is no way, i'll declare my entire model class as an Entity... :/. Thanks in advance.

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.

Get Object from Field

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

Categories

Resources