Passing a list of base class objects to a method and using instanceof to filter
up vote
-1
down vote
favorite
I'm working on a Java reverse engineering project, where I am analyzing bytecode and trying to identify classes, methods and fields using the ASM framework. After identifying these I transform some classes to implement my custom interfaces with, e.g., getter methods.
For identifying classes, I have created an abstract class Analyzer
with an abstract method for running the analysis on a collection of classes. Child classes of Analyzer
try to identify a certain class/field/method of interest. For instance, AnimalAnalyzer
attempts to identify the class which represents an animal.
After running the analyzers, I inject my own interfaces and their implementations into the classes. Similarly to Analyzer
, I have created an Injector
interface with an inject(List<Analyzer> analyzers)
method. For each class that I want to inject there is a separate class which implements the interface, e.g., AnimalInjector
. The injector iterates the list of Analyzers, which contain the results of their analysis, and uses the relevant ones by checking their type with the instanceof
operator. By "relevant ones" I mean the analyzers which contain the information needed to generate the bytecode with.
public abstract class Analyzer {
public abstract void run(ClassCollection classCollection);
}
public class AnimalAnalyzer extends Analyzer {
private ClassNode identifiedClass = null;
@Override
public void run(ClassCollection classCollection) {
for (ClassNode classNode : classCollection.getAllClassNodes()) {
boolean isMatch = doesClassMatch(classNode); // method omitted from example
if (isMatch) {
identifiedClass = classNode;
break;
}
}
}
}
public interface Injector {
void inject(List<Analyzer> analyzers);
}
public class AnimalInjector implements Injector {
@Override
public void inject(List<Analyzer> analyzers) {
AnimalAnalyzer animalAnalyzer = null;
for (Analyzer analyzer : analyzers) {
if (analyzer instanceof AnimalAnalyzer) {
animalAnalyzer = (AnimalAnalyzer) analyzer;
}
}
if (animalAnalyzer == null) {
throw new IllegalStateException("AnimalAnalyzer not found in list");
}
... (bytecode generation and injection)
}
}
One of the reasons that I chose to do it this way is that the analyzers have to be run in a specific order. For example, to identify a Dog
which extends Animal
, the latter has to be found first. For this purpose I created MasterAnalyzer
, which stores a list of the analyzers in a specific order. When run
is invoked on this analyzer, it calls run on the analyzers in the list in the right order.
public class MasterAnalyzer extends Analyzer {
private List<Analyzer> analyzers = new ArrayList<>();
public MasterAnalyzer() {
analyzers.add(new AnimalAnalyzer());
analyzers.add(new DogAnalyzer());
... (more analyzers)
}
public List<Analyzer> getAnalyzers() {
return analyzers;
}
@Override
public void run(ClassCollection classCollection) {
for (Analyzer analyzer : analyzers) {
analyzer.run(classCollection);
}
}
}
The injectors, in turn, can all be run with the same command: inject(masterAnalyzers.getAnalyzers())
. While this makes it easy at the client side, it causes the injectors to know more than they need to know. For instance, let's assume that we also have a CatAnalyzer
. Now, when we run the DogInjector
, the list of analyzers will include the CatAnalyzer
, even though the DogInjector
does not care about it. This, along with the nasty instanceof
usages, causes red signals to me. Now I am reaching out to you more experienced developers for some tips on how to improve my design. While searching for alternative ways, I found the Visitor pattern, which could be applicable here. However, I am still unsure how to apply it and whether it would improve my design or not.
java design-patterns polymorphism
New contributor
add a comment |
up vote
-1
down vote
favorite
I'm working on a Java reverse engineering project, where I am analyzing bytecode and trying to identify classes, methods and fields using the ASM framework. After identifying these I transform some classes to implement my custom interfaces with, e.g., getter methods.
For identifying classes, I have created an abstract class Analyzer
with an abstract method for running the analysis on a collection of classes. Child classes of Analyzer
try to identify a certain class/field/method of interest. For instance, AnimalAnalyzer
attempts to identify the class which represents an animal.
After running the analyzers, I inject my own interfaces and their implementations into the classes. Similarly to Analyzer
, I have created an Injector
interface with an inject(List<Analyzer> analyzers)
method. For each class that I want to inject there is a separate class which implements the interface, e.g., AnimalInjector
. The injector iterates the list of Analyzers, which contain the results of their analysis, and uses the relevant ones by checking their type with the instanceof
operator. By "relevant ones" I mean the analyzers which contain the information needed to generate the bytecode with.
public abstract class Analyzer {
public abstract void run(ClassCollection classCollection);
}
public class AnimalAnalyzer extends Analyzer {
private ClassNode identifiedClass = null;
@Override
public void run(ClassCollection classCollection) {
for (ClassNode classNode : classCollection.getAllClassNodes()) {
boolean isMatch = doesClassMatch(classNode); // method omitted from example
if (isMatch) {
identifiedClass = classNode;
break;
}
}
}
}
public interface Injector {
void inject(List<Analyzer> analyzers);
}
public class AnimalInjector implements Injector {
@Override
public void inject(List<Analyzer> analyzers) {
AnimalAnalyzer animalAnalyzer = null;
for (Analyzer analyzer : analyzers) {
if (analyzer instanceof AnimalAnalyzer) {
animalAnalyzer = (AnimalAnalyzer) analyzer;
}
}
if (animalAnalyzer == null) {
throw new IllegalStateException("AnimalAnalyzer not found in list");
}
... (bytecode generation and injection)
}
}
One of the reasons that I chose to do it this way is that the analyzers have to be run in a specific order. For example, to identify a Dog
which extends Animal
, the latter has to be found first. For this purpose I created MasterAnalyzer
, which stores a list of the analyzers in a specific order. When run
is invoked on this analyzer, it calls run on the analyzers in the list in the right order.
public class MasterAnalyzer extends Analyzer {
private List<Analyzer> analyzers = new ArrayList<>();
public MasterAnalyzer() {
analyzers.add(new AnimalAnalyzer());
analyzers.add(new DogAnalyzer());
... (more analyzers)
}
public List<Analyzer> getAnalyzers() {
return analyzers;
}
@Override
public void run(ClassCollection classCollection) {
for (Analyzer analyzer : analyzers) {
analyzer.run(classCollection);
}
}
}
The injectors, in turn, can all be run with the same command: inject(masterAnalyzers.getAnalyzers())
. While this makes it easy at the client side, it causes the injectors to know more than they need to know. For instance, let's assume that we also have a CatAnalyzer
. Now, when we run the DogInjector
, the list of analyzers will include the CatAnalyzer
, even though the DogInjector
does not care about it. This, along with the nasty instanceof
usages, causes red signals to me. Now I am reaching out to you more experienced developers for some tips on how to improve my design. While searching for alternative ways, I found the Visitor pattern, which could be applicable here. However, I am still unsure how to apply it and whether it would improve my design or not.
java design-patterns polymorphism
New contributor
add a comment |
up vote
-1
down vote
favorite
up vote
-1
down vote
favorite
I'm working on a Java reverse engineering project, where I am analyzing bytecode and trying to identify classes, methods and fields using the ASM framework. After identifying these I transform some classes to implement my custom interfaces with, e.g., getter methods.
For identifying classes, I have created an abstract class Analyzer
with an abstract method for running the analysis on a collection of classes. Child classes of Analyzer
try to identify a certain class/field/method of interest. For instance, AnimalAnalyzer
attempts to identify the class which represents an animal.
After running the analyzers, I inject my own interfaces and their implementations into the classes. Similarly to Analyzer
, I have created an Injector
interface with an inject(List<Analyzer> analyzers)
method. For each class that I want to inject there is a separate class which implements the interface, e.g., AnimalInjector
. The injector iterates the list of Analyzers, which contain the results of their analysis, and uses the relevant ones by checking their type with the instanceof
operator. By "relevant ones" I mean the analyzers which contain the information needed to generate the bytecode with.
public abstract class Analyzer {
public abstract void run(ClassCollection classCollection);
}
public class AnimalAnalyzer extends Analyzer {
private ClassNode identifiedClass = null;
@Override
public void run(ClassCollection classCollection) {
for (ClassNode classNode : classCollection.getAllClassNodes()) {
boolean isMatch = doesClassMatch(classNode); // method omitted from example
if (isMatch) {
identifiedClass = classNode;
break;
}
}
}
}
public interface Injector {
void inject(List<Analyzer> analyzers);
}
public class AnimalInjector implements Injector {
@Override
public void inject(List<Analyzer> analyzers) {
AnimalAnalyzer animalAnalyzer = null;
for (Analyzer analyzer : analyzers) {
if (analyzer instanceof AnimalAnalyzer) {
animalAnalyzer = (AnimalAnalyzer) analyzer;
}
}
if (animalAnalyzer == null) {
throw new IllegalStateException("AnimalAnalyzer not found in list");
}
... (bytecode generation and injection)
}
}
One of the reasons that I chose to do it this way is that the analyzers have to be run in a specific order. For example, to identify a Dog
which extends Animal
, the latter has to be found first. For this purpose I created MasterAnalyzer
, which stores a list of the analyzers in a specific order. When run
is invoked on this analyzer, it calls run on the analyzers in the list in the right order.
public class MasterAnalyzer extends Analyzer {
private List<Analyzer> analyzers = new ArrayList<>();
public MasterAnalyzer() {
analyzers.add(new AnimalAnalyzer());
analyzers.add(new DogAnalyzer());
... (more analyzers)
}
public List<Analyzer> getAnalyzers() {
return analyzers;
}
@Override
public void run(ClassCollection classCollection) {
for (Analyzer analyzer : analyzers) {
analyzer.run(classCollection);
}
}
}
The injectors, in turn, can all be run with the same command: inject(masterAnalyzers.getAnalyzers())
. While this makes it easy at the client side, it causes the injectors to know more than they need to know. For instance, let's assume that we also have a CatAnalyzer
. Now, when we run the DogInjector
, the list of analyzers will include the CatAnalyzer
, even though the DogInjector
does not care about it. This, along with the nasty instanceof
usages, causes red signals to me. Now I am reaching out to you more experienced developers for some tips on how to improve my design. While searching for alternative ways, I found the Visitor pattern, which could be applicable here. However, I am still unsure how to apply it and whether it would improve my design or not.
java design-patterns polymorphism
New contributor
I'm working on a Java reverse engineering project, where I am analyzing bytecode and trying to identify classes, methods and fields using the ASM framework. After identifying these I transform some classes to implement my custom interfaces with, e.g., getter methods.
For identifying classes, I have created an abstract class Analyzer
with an abstract method for running the analysis on a collection of classes. Child classes of Analyzer
try to identify a certain class/field/method of interest. For instance, AnimalAnalyzer
attempts to identify the class which represents an animal.
After running the analyzers, I inject my own interfaces and their implementations into the classes. Similarly to Analyzer
, I have created an Injector
interface with an inject(List<Analyzer> analyzers)
method. For each class that I want to inject there is a separate class which implements the interface, e.g., AnimalInjector
. The injector iterates the list of Analyzers, which contain the results of their analysis, and uses the relevant ones by checking their type with the instanceof
operator. By "relevant ones" I mean the analyzers which contain the information needed to generate the bytecode with.
public abstract class Analyzer {
public abstract void run(ClassCollection classCollection);
}
public class AnimalAnalyzer extends Analyzer {
private ClassNode identifiedClass = null;
@Override
public void run(ClassCollection classCollection) {
for (ClassNode classNode : classCollection.getAllClassNodes()) {
boolean isMatch = doesClassMatch(classNode); // method omitted from example
if (isMatch) {
identifiedClass = classNode;
break;
}
}
}
}
public interface Injector {
void inject(List<Analyzer> analyzers);
}
public class AnimalInjector implements Injector {
@Override
public void inject(List<Analyzer> analyzers) {
AnimalAnalyzer animalAnalyzer = null;
for (Analyzer analyzer : analyzers) {
if (analyzer instanceof AnimalAnalyzer) {
animalAnalyzer = (AnimalAnalyzer) analyzer;
}
}
if (animalAnalyzer == null) {
throw new IllegalStateException("AnimalAnalyzer not found in list");
}
... (bytecode generation and injection)
}
}
One of the reasons that I chose to do it this way is that the analyzers have to be run in a specific order. For example, to identify a Dog
which extends Animal
, the latter has to be found first. For this purpose I created MasterAnalyzer
, which stores a list of the analyzers in a specific order. When run
is invoked on this analyzer, it calls run on the analyzers in the list in the right order.
public class MasterAnalyzer extends Analyzer {
private List<Analyzer> analyzers = new ArrayList<>();
public MasterAnalyzer() {
analyzers.add(new AnimalAnalyzer());
analyzers.add(new DogAnalyzer());
... (more analyzers)
}
public List<Analyzer> getAnalyzers() {
return analyzers;
}
@Override
public void run(ClassCollection classCollection) {
for (Analyzer analyzer : analyzers) {
analyzer.run(classCollection);
}
}
}
The injectors, in turn, can all be run with the same command: inject(masterAnalyzers.getAnalyzers())
. While this makes it easy at the client side, it causes the injectors to know more than they need to know. For instance, let's assume that we also have a CatAnalyzer
. Now, when we run the DogInjector
, the list of analyzers will include the CatAnalyzer
, even though the DogInjector
does not care about it. This, along with the nasty instanceof
usages, causes red signals to me. Now I am reaching out to you more experienced developers for some tips on how to improve my design. While searching for alternative ways, I found the Visitor pattern, which could be applicable here. However, I am still unsure how to apply it and whether it would improve my design or not.
java design-patterns polymorphism
java design-patterns polymorphism
New contributor
New contributor
New contributor
asked 4 hours ago
Markus Kullberg
1
1
New contributor
New contributor
add a comment |
add a comment |
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Markus Kullberg is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209867%2fpassing-a-list-of-base-class-objects-to-a-method-and-using-instanceof-to-filter%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Markus Kullberg is a new contributor. Be nice, and check out our Code of Conduct.
Markus Kullberg is a new contributor. Be nice, and check out our Code of Conduct.
Markus Kullberg is a new contributor. Be nice, and check out our Code of Conduct.
Markus Kullberg is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209867%2fpassing-a-list-of-base-class-objects-to-a-method-and-using-instanceof-to-filter%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown