Virtual behavior with java's inheritance with Generic parent - java

I have a "Data manager" class, which contains a list of some sort of object type
Then, when I started getting my code advanced, I had the need for a different kind of manager, which has some similarities - loadData(..), saveData(..), add(..), remove(..)
but also some differences, which is unique to each kind of manager, depending on the type of which it is "managing".
So I decided to do the following structure:
Generic class with singelton implementation for each child (At first, my manager was static as it has no sense of being multiple instances):
public abstract class GenericDataManager<T> {
protected List<T> list;
protected void saveData(Context context, String filePath) {..}
protected void loadData(Context context, String filePath) {..}
..
}
and my two managers are the following:
public class ManagerA extends GenericDataManager<A> {
private static ManagerA instance = null;
protected ManagerA() { }
public static ManagerA getInstance() {
if (instance == null)
instance = new ManagerA();
return instance;
}
private void saveData(Context context) {
saveData(context, "fileA");
}
private void loadData(Context context) {
loadData(context, "fileA");
}
}
public class ManagerB extends GenericDataManager<B> {
private static ManagerB instance = null;
protected ManagerB() { }
public static ManagerB getInstance() {
if (instance == null)
instance = new ManagerB();
return instance;
}
private void saveData(Context context) {
saveData(context, "fileB");
}
private void loadData(Context context) {
loadData(context, "fileB");
}
}
I showed here only the similar pieces of code for the two managers, and you can already see the problem - Although I managed to make my similar piece of code implemented only one and reused for every specific implementation using generics and inheritance mechanism, I still need the only specific information, which is the data file to use.
Is there a way of the generic parent to request that information from its child, so that I wont need the redundant implementation in the child class?
Leaving it this way makes me feel Im missing something.

How about:
public abstract class GenericDataManager<T> {
protected abstract String getFilePath();
protected List<T> list;
protected void saveData(Context context) {
String filePath = getFilePath();
..
}
protected void loadData(Context context) {
String filePath = getFilePath();
..
}
..
}
and then:
public class ManagerA extends GenericDataManager<A> {
private static ManagerA instance = null;
protected ManagerA() { }
public static ManagerA getInstance() {
if (instance == null)
instance = new ManagerA();
return instance;
}
protected String getFilePath() { return "fileA" );
}
public class ManagerB extends GenericDataManager<A> {
private static ManagerB instance = null;
protected ManagerB() { }
public static ManagerB getInstance() {
if (instance == null)
instance = new ManagerB();
return instance;
}
protected String getFilePath() { return "fileB" );
}

You could have the parent call back to the children, but it's generally poor practice. Inheritance always requires tightly coupling the children to the parent, but you generally want to avoid coupling the parent to the children.
Instead, perhaps in GenericDataManager:
protected void saveData(Context context, string fileName) {
// do the generic work with the specific given file
}
protected void loadData(Context context) {
// do the generic work with the specific given file
}
...and then in the subclasses:
private void loadData(Context context) {
super.loadData(context, "loadA"); // or of course, "loadB"
}

Yes. Make an abstract getter in the parent class, and add implementation in children:
abstract class GenericDataManager<T> {
protected void saveData(Context context) {
String filePath = getFilePath();
}
protected void loadData(Context context) {
String filePath = getFilePath();
}
protected abstract String getFilePath();
}
public class ManagerA extends GenericDataManager<A> {
#Override protected String getFilePath() {
return "fileA";
}
}

Related

Raw use of parameterized class - when returning base class with generic parameter with factory design pattern

Background
I learned Factory pattern, and the power of generics and I'm attempting to piece them together.
Here are my efforts
Without generic input parameter - No warnings
public abstract class ArtifactCreator {
public abstract void setArtifacts(String workflowInput);
}
public class FooArtifactCreator extends ArtifactCreator {
#Override
public void setArtifacts(String input) {
return null;
}
}
public class BarArtifactCreator extends ArtifactCreator {
#Override
public void setArtifacts(String input) {
return null;
}
}
public class Factory {
public ArtifactCreator getArtifactCreator(String domain) {
if (domain == "foo") {
return new FooArtifactCreator()
} else if (domain == "bar") {
return new BarArtifactCreator()
}
return null;
}
}
My whole problem is the workflowInput is relegated to the type String. But I want it to be some generic POJO.
With generics - I get warnings in Factory.java and Store.java that I want to get rid of correctly. (I want to be using generics for my use-case the right way).
Raw use of parameterized class 'ArtifactCreator' on both the files in Store.java and Factory.java
Unchecked call to 'setArtifacts(T)' as a member of raw type 'ArtifactCreator' in Store.java
public abstract class ArtifactCreator {
public abstract void setArtifacts(T workflowInput);
}
public class FooArtifactCreator extends ArtifactCreator<FooInput> {
#Override
public void setArtifacts(FooInput input) {
return null;
}
}
public class BarArtifactCreator extends ArtifactCreator<BarInput> {
#Override
public void setArtifacts(BarInput input) {
return null;
}
}
public class Factory {
public ArtifactCreator getArtifactCreator(String domain) {
if (domain == "foo") {
return new FooArtifactCreator()
} else if (domain == "bar") {
return new BarArtifactCreator()
}
return null;
}
}
public class Input {
private String domain;
private String otherInput;
}
public class Store {
private final Factory factory;
public Store(Factory factory) {
this.factory = factory;
}
public ArtifactCreator getCaseClosureArtifactFactory(Input req) {
ArtifactCreator artifactCreator = factory.setArtifacts(req.getDomain());
//In reality - Create either FooInput or BarInput depending on
//`otherInput` field in `Input` POJO. Assume that there will be another
//factory/HashMap to return the input needed
FooInput input = new FooInput();
artifactCreator.setArtifacts(input);
}
}
One way I can think of solving my problems is do something like:
public class WorkflowInput {
private FooInput input;
private BarInput input;
}
public abstract class ArtifactCreator {
public abstract void setArtifacts(WorkflowInput workflowInput);
}
public class FooArtifactCreator extends ArtifactCreator {
#Override
public void setArtifacts(WorkflowInput input) {
FooInput input = input.getFooInput(); //Extract specific input
}
}
public class BarArtifactCreator extends ArtifactCreator {
#Override
public void setArtifacts(WorkflowInput input) {
BarInput input = input.getBarInput(); //Extract specific input
}
}
This feels a bit unecessary to keep some fields in WorkflowInput null.

Handle duplicate code in concrete implementations of an interface in Spring boot application

I am working on a spring boot application, where I have an interface I as follows:
public interface I {
String getType();
void f1();
}
There are two classes implementing interface I as follows:
#Component
class A implements I {
private final MyRepo1 myRepo1;
private final Helper helper;
public A(MyRepo1 myRepo1, Helper helper) {
this.myRepo1 = myRepo1;
this.helper = helper;
}
#Override
public String getType() {
return "type1";
}
#Override
public void f1(String type) {
int response = helper.f1(type);
if(response != -1) {
return;
}
//Add type1 specific handling here
}
}
One more class B implementing interface I as follows:
#Component
class B implements I {
private final MyRepo2 myRepo2;
private final Helper helper;
public B(MyRepo2 myRepo2, Helper helper) {
this.myRepo2 = myRepo2;
this.helper = helper;
}
#Override
public String getType() {
return "type2";
}
#Override
public void f1(String type) {
int response = helper.f1(type);
if(response != -1) {
return;
}
//Add type2 specific handling here
}
}
Helper is as follows:
#Component
class Helper {
public int f1(String type) {
...
}
}
I have a factory class as follows, that is used to fetch an object of the appropriate type:
#Component
public class ServiceFactory {
private final Map<String, I>
typeToClassMap = new HashMap<>();
public ServiceFactory(List<I> components) {
for(I component : components) {
typeToClassMap.put(component.getType(), component);
}
}
}
This ServiceFactory is basically used to get objects according to the type.
Now, the problem is, here for sake of simplicity I have just shown two classes implementing the interface. But actually, I have a lot more classes than this, implementing the interface I.
Some of the classes may have the same implementation of f1(), resulting in duplicate code.
I cannot make f1() as the default method in interface I as this requires the dependent bean.
I cannot understand what is the best way to handle this.
Could anyone please help here?

How to access super class' super class in a Sonar Custom rule?

I'm writing a custom rule that will check whether the class under analysis is extending a type.
For example:
class Bus {
}
class Transport {
}
class PublicTransport extends Transport {
}
class Bus should extend class Transport or a sub class of Transport.
public class EnsureSuperClassRule extends IssuableSubscriptionVisitor {
final String SUPER_CLASS = "common.service.SuperService";
#Override
public List<Tree.Kind> nodesToVisit() {
return ImmutableList.of(Tree.Kind.CLASS);
}
#Override
public void visitNode(Tree tree) {
ClassTree classTree = (ClassTree) tree;
String className = classTree.simpleName().name();
if (className.endsWith("Service")) {
if(classTree.superClass() == null) {
return false;
}
if (!SUPER_CLASS.equals(localClassTree.superClass().symbolType().fullyQualifiedName())) {
reportIssue(tree, String.format("The class should extend SuperService or a class of type SuperService"));
}
}
}
}
}
How can I get the information related to superclass of the superclass?
You can simply call
Class superClassOfSuperClass = this.class().getSuperClass();
superClassOfSuperClass.method().invoke(this);
I'm not sure with your above example as there is a few typo's or misunderstanding with inheritance
You can collect all super classes until java.lang.Object was reached like so:
#Override
public void visitNode(Tree pTree) {
final ClassTree classTree = (ClassTree) pTree;
final Set<String> superclasses = new HashSet<>();
Type currentSuperclass = classTree.symbol().superClass();
while (currentSuperclass != null) {
superclasses.add(currentSuperclass.fullyQualifiedName());
currentSuperclass = currentSuperclass.symbol().superClass();
}
// ... do something with superClasses
super.visitNode(pTree);
}
#Override
public List<Kind> nodesToVisit() {
return ImmutableList.of(Tree.Kind.CLASS);
}
(Tested with sonar-java-plugin 6.3.0 and sonar-plugin-api 8.2.0)

How to take R.string value instead of hardcoded value, if it's a class field?

For instance I want to take this
public class SomeClass {
public static final String GREET_STRING = "Hello!";
//...
and change it to something like:
public class SomeClass {
public static final String GREET_STRING = getString(R.string.greet_string);
//...
Can this be done or do I need some kind of Context instantiation to get the resources for the string loading?
To use getString() you will need a context. A Resource string cannot be static final because it is possible for String resources to change as you change Locales (if you have multiple String files such as strings.xml (us) and strings.xml (uk))
Try this:
public abstract class SomeClass extends AppCompatActivity {
public static String GREET_STRING(Context context) {
if (context == null) {
return null;
}
return context.getResources().getString(R.string.greet_string);
}
}
Res/Value/String:
<resources>
<string name="greet_string">Hello!</string>
</resources>
Call SomeClass from MainClass
public class MainClass extends SomeClass {
private final static String TAG = MainClass.class.getName();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// call SomeClass from MainClass
Log.i(TAG, SomeClass.GREET_STRING(this));
}
}
There are two ways access the string inside the class which is not extending Activity or Fragment.
Pass Context or Activity to class constructor
public class SomeClass {
private Context context;
public SomeClass(Context context) {
this.context = context;
}
public static final String GREET_STRING = context.getString(R.string.greet_string);
}
The second way is if you don`t want to pass context to class. You need to create an instance of the Application and static function get instance.
public class App extends Application {
private static App instance = null;
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public static App getInstance() {
// Return the instance
return instance;
}
}
public class SomeClass {
public static final String GREET_STRING = App.getInstance().getString(R.string.greet_string);
}

Where is onStartLoading() and forceLoad() called and implemented?

I'm implementing LoaderManager.LoaderCallbacks on my MainActivity and I'm overriding onCreateLoader. In the onCreateLoader I simply return a AsyncTaskLoader object, where I override the onStartLoading method, in which I check if the query is null. For this code works, I need to call forceLoad(). Here is a snippet of the code:
#Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
return new AsyncTaskLoader<String>(this) {
#Override
protected void onStartLoading() {
// No need to peform a query if no arguments were passed
if (args == null) {
return;
}
// This needs to be called!!
forceLoad();
}
#Override
public String loadInBackground() {
/* some code */
}
};
}
The problem is that I don't know why I need to call forceLoad(), because its implementation is a "empty" method. In the source code of the Loader Class, the implementation of forceLoad is:
public void forceLoad() {
onForceLoad();
}
and the implementation of onForceLoad() is:
protected void onForceLoad() {
}
I tried to find some methods that override forceLoad() or onForceLoad in the other parts of the code (I use (getSupportLoaderManager().initLoader(arg1, arg2, arg3)), but until this moment have not succeeded. Why do I have to call forceLoad() and why does it work?
The reason Loader class is having empty implementation of onForceLoad() is that Loader is a base class. Their child classes are supposed to be implementing onForceLoad().
If we will see your code, you are using AsyncTaskLoader which basically a child of Loader so AsyncTaskLoader will have the onForceLoad() implementation which is actually this:
#Override
protected void onForceLoad() {
super.onForceLoad();
cancelLoad();
mTask = new LoadTask();
if (DEBUG) Slog.v(TAG, "Preparing load: mTask=" + mTask);
executePendingTask();
}
Your onCreateLoader()basically should be like this:
public Loader<String> onCreateLoader(int id, final Bundle args) {
AsyncTaskLoader<String> loader = new AsyncTaskLoader<String>(this) {
#Override
protected void onStartLoading() {
// No need to peform a query if no arguments were passed
if (args == null) {
return;
}
}
#Override
public String loadInBackground() {
/* some code */
}
};
loader.forceLoad(); // This basically gonna run the loader.
return loader;
}
We can also override the onStartLoading() method to call forceLoad() which is a required step to actually trigger the loadInBackground() method to execute.
public class Loader extends AsyncTaskLoader<List<data>> {
// Tag for Log messages
private static final String LOG_TAG = Loader.class.getName();
// Query URL
private String mUrl;
/**
* Constructs a new {#link data}
*
* #param context of the activity
* #param url to load the data from
*/
public Loader (Context context, String url) {
super(context);
mUrl = url;
}
#Override
protected void onStartLoading() {
forceLoad();
}
/**
* This is on the background thread
*/
#Override
public List<data> loadInBackground() {
if(mUrl == null) {
return null;
}
// Perform the network request, parse the response and extract a list of data.
List<data> data= QueryUtils.fetchData(mUrl);
return data;
}
}

Categories

Resources