Java: separate main logic & exception-handling logic - java

Question: how to move all logic to strategy (another class) but leave exception-handling logic in class-owner?
I've got: method map which gets data array from input argument, and then perform a lot of logic on that:
class Owner ...
public void map(final LongWritable key, final Text value, final Context context) {
// 1st-fragment of code
String[] data = null;
try { // Not Owner class logic, should be moved to strategy
StringReader reader = new StringReader(line);
CustomParser cParser = new CustomParser(reader,_strategy);
data = cParser.getLine();
} catch (final IOException e) {
outputBadData(line); // Owner class logic
return;
}
// 2nd-fragment of code: logic which is based on `data` array
................
................
}
I want: Actually all logic in 1st fragment (except outputBadData) doesn't belong to this class. I want to move it strategies. It'll look like:
public void map(final LongWritable key, final Text value, final Context context) {
// 1st-fragment of code
String[] data = strategy.getData(value);
// 2nd-fragment of code: logic which is based on `data` array
................
................
}
Problem: outputBadData is a logic of Owner class, not the strategy.

If I've understood right, you must create your Strategy class and define within it a method with required logic.
In this method's signature define 'throws IOException'
for example:
public [return type] readLine(arguments...) throws IOException {
...
}
Also you must have the reference to an object of your new class(Strategy) to invoke the 'readLine' method.
You can store this object as field of Owner class passing it as constructor argument (for using setter method) when you create the instance of this class. And then, in your 'map' method of Owner class, surround the 'readLine' method invocation with 'try-catch' block to handle exception:
try{
strategyReference.readLine(arguments...);
}catch (IOException e) {
outputBadData(line);
return;

Related

Java: How to fix code duplication in multiple methods?

I have some theoretical knowledge related to Design Patterns and now I have some issues to make these info and another ones in action.
I have the following 2 methods in my ServiceImpl class:
#Override
public MultipartFile exportA() throws IOException {
// repeated lines-I same as exportB method (code omitted for brevity)
// other lines special to exportA method
// repeated lines-II same as exportB method (code omitted for brevity)
}
#Override
public MultipartFile exportB() throws IOException {
// repeated lines-I same as exportA method (code omitted for brevity)
// other lines special to exportB method
// repeated lines-II same as exportA method (code omitted for brevity)
}
As it is shown, there are repeated parts in all of these methods. So, should I create 2 methods for repeated lines-I and II, eand then move these code blocks to these newly created 2 methods? Or, is there a better way for Design Patterns?
If I have well understood your statement, this sounds to me a
Builder Pattern that you are looking for. You methods are building a MultipartFile whereas the build process itself depends on 'arguments/parameters' (here I guess sheet file path) and distinct code (the one you referred to as "other lines special to this method").
For that I would create a class MultipartFileBuilder that does the staff and that I would call in each method; of course, by means of setting the appropriate parameters and "code" each time. The code is simply an implementation of the java.util.function.Consumer<T> functional interface used in the following code (*2) and other parameters are using simple setters as well (here (*1)).
Note that I invoked the Consumer<T> as lambda expression here (the c->... construct). And note also that the type parameter <T> in Consumer<T> here is a new class I introduced MultipartFileBuildContext to allow multiple information to be passed to the code you are willing to write in each method. I guest the 'sheet' var would be a starting point. You can add other information if you need to.
To summer up things, this is how the code would look :
#Override
public MultipartFile exportMethodA() throws IOException {
return new MultipartFileBuilder()
.setSheetPath("sheetA/path") (*1)
.setAction(c->{
//(*2) do your staff here for method A
// the "other lines special to this method"
XSSFSheet sheet=c.getSheet()
...
}).build();
}
#Override
public MultipartFile exportMethodB() throws IOException {
return new MultipartFileBuilder()
.setSheetPath("sheetB/path") (*1)
.setAction(c->{
//(*2) do your staff here for method B
// the "other lines special to this method"
XSSFSheet sheet=c.getSheet()
...
}).build();
}
class MultipartFileBuildContext {
private XSSFSheet sheet;
public MultipartFileBuildContext(XSSFSheet sheet){this.sheet=sheet;}
public String getSheetPath() {
return sheetPath;
}
}
class MultipartFileBuilder {
String sheetPath;
Consumer<MultipartFileBuildContext> action;
public String getSheetPath() {
return sheetPath;
}
public MultipartFileBuilder setSheetPath(String sheetPath) {
this.sheetPath = sheetPath;
return this;
}
public Consumer<MultipartFileBuildContext> getAction() {
return action;
}
public MultipartFileBuilder setAction(Consumer<MultipartFileBuildContext> action) {
this.action = action;
return this;
}
public MockMultipartFile build() {
// repeated lines
workbook = new XSSFWorkbook();
sheet = workbook.createSheet(sheetPath);
//
if(action!=null){
MultipartFileBuildContext c=new MultipartFileBuildContext(sheet);
action.accept(c);
}
// repeated lines ======================================================
outputFile = File.createTempFile(...);
try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
workbook.write(outputStream);
} catch (IOException e) {
LoggingUtils.error("Writing failed ", e);
}
final FileInputStream input = new FileInputStream(outputFile);
final String fileName = TextBundleUtil.read(...);
return new MockMultipartFile(fileName,
fileName, CONTENT_TYPE, IOUtils.toByteArray(input));
//
}
}
At the end, this pattern needs to be used with care because you need to factorize all that you can to make the builder really useful, but not too much to make it a "boat of anything". For instance, you can have as input the sheet path or an inputstream of it to make it more useful/generic.

How to wrap exceptions handling in helper class with lambda expressions

I am having troubles while trying to refactor exception handling logic in an helper class.
My code uses a repository which accesses a database and might throw the custom exception RepositoryException. If such exception is thrown by the repository, I want my code to catch it and set an error label in the graphical user interface (view):
... // more code
try {
existingCourse = repository.findByTitle(course.getTitle()); // <- throws RepositoryException
} catch (RepositoryException e) {
view.showError(e.getMessage(), course);
return;
}
... // some more code
The point is that this code is repeated several times and I would prefer to have it refactored in an helper class.
This is what I came up to after some experiments:
A custom FunctionalInterface called ThrowingSupplier, which represent the code that throws the exception.
A TransactionManager helper class, with a catcher methods that accepts a ThrowingSupplier
This is the related code (BaseEntity is just a base class for entities in my domain, as you might guess):
// ThrowingSupplier.java
#FunctionalInterface
public interface ThrowingSupplier<T extends BaseEntity> {
T get() throws RepositoryException;
}
/* ------------------------------------------------------ */
// ExceptionManager.java
public final class ExceptionManager<T extends BaseEntity> {
private T result;
private String exceptionMessage;
ExceptionManager() {
}
public boolean catcher(ThrowingSupplier<T> supplier) {
try {
clearResult();
clearExceptionMessage();
result = supplier.get();
return true;
} catch (RepositoryException e) {
exceptionMessage = e.getMessage();
}
return false;
}
// public getters and 'clearers' for attributes
...
}
And this is how I am using this now:
...
em = new ExceptionManager();
... // more code
if (!em.catcher(() -> repository.findByTitle(course.getTitle()))) {
view.showError(em.getExceptionMessage(), course);
return;
}
existingCourse = em.getResult();
... // some more code
Now it seems to me that this does not give any advantages with respect to using directly the try catch in every repository invocation. This is mainly because I need both the return value of the repository method and a way to tell the caller if the repository call has been successful. As a variation I tried to add the showError call inside catcher, but then I must pass view and entity in every invocation of catcher, which I do not like very much as it makes the code less readable.
Is there another way to accomplish this in an elegant manner or it is better to leave the try catch in every call to the repository? Also, what is the standard way to deal with this problem?

Putting methods that handle HashMap of all instances of a class in a separate class

I have a class that creates index cards, and within it, I have an instance variable that is a static HashMap that stores all the instances created.
I have been thinking a lot about it and I thought that the methods that handle the opperations over that HashMap should go in a different class, because those methods don't opperate directly over any index card, they opperate over the list of index cards.
This way, I would have an IndexCard class, and an ListAdministrator class. And both classes would handle different functions.
The problem is that this new class (ListAdministrator) would only have static methods, because there is only one list and there is no reason to create any new list of index cards, I only need one.
Should I move those methods to another class or should I keep it like this? Is that a good practice?
This is the code:
class IndexCard {
public static HashMap <String, IndexCard> list = new HashMap <> ();
public String name;
public String address;
public String phone;
public String email;
public LocalDate dateRegister;
IndexCard(String name, String dni, String address, String phone, String email) {
this.name = name;
this.address = address;
this.phone = phone;
this.email = email;
dateRegister = LocalDate.now();
if (Utils.validarDni(dni) && !list.containsKey(dni)) {
list.put(dni, this);
} else {
throw new InvalidParameterException ("Error when entering the data or the DNI has already been previously registered");
}
}
/**
* Update the data of the selected card.
*/
public void update() throws IllegalAccessException {
String key = getKeyWithObject(this);
Scanner reader = new Scanner(System.in);
Field[] fields = this.getClass().getFields();
for (Field field: fields) {
String nameField = Utils.splitCamelCase(field.getName());
if (!Modifier.isStatic(field.getModifiers()) && (field.getType()).equals(String.class)) {
System.out.println ("Enter new " + nameField);
String value = reader.nextLine().trim();
field.set(this, value);
}
}
reader.close();
list.put(key, this);
System.out.println("Updated data \n \n");
}
/**
* Delete the selected card.
*/
public void delete() throws IllegalAccessException {
String key = getKeyWithObject(this);
Field [] fields = this.getClass().getFields();
for (Field field: fields) {
if (!Modifier.isStatic(field.getModifiers())) {
field.set(this, null);
}
}
list.remove(key);
}
/**
* Displays the data of the selected card on screen.
*/
public void print() throws IllegalAccessException {
Field [] fields = this.getClass().getFields();
for (Field field: fields) {
if (!Modifier.isStatic(field.getModifiers())) {
String nameFieldConSpaces = Utils.splitCamelCase(field.getName());
Object value = field.get(this);
System.out.println(nameFieldConSpaces + ":" + value);
}
}
}
/**
* Print all the entries of the desired sublist with the ID, Name and phone number.
*/
public static <T extends IndexCard> void SubClasslist (Class <T> subClass) {
for (HashMap.Entry <String, IndexCard> entry: list.entrySet ()) {
String key = entry.getKey ();
IndexCard card = entry.getValue ();
if (card.getClass().equals(subClass)) {
System.out.println ("ID:" + key + "| Name:" + card.name + "| Phone:" + card.phone);
}
}
}
/**
* Returns the object stored in the list of cards when entering the corresponding key.
*/
public static IndexCard GetObjetWithKey(String key) {
try {
return list.get(key);
} catch (IllegalArgumentException e) {
System.out.println (e + ": The indicated key does not appear in the database.");
return null;
}
}
/**
* Obtain the Key when entering the corresponding card.
*/
public static String getKeyWithObject (Object obj) {
for (HashMap.Entry <String, IndexCard> entry: list.entrySet()) {
if (obj.equals(entry.getValue())) {
return entry.getKey();
}
}
throw new IllegalArgumentException ("The indicated data does not appear in the database, and therefore we could not obtain the key.");
}
/**
* Returns a list of cards when entering the main data of the card.
* #param data Corresponds to the identifying name of the file.
*/
public static ArrayList <IndexCard> SearchByName (String data) {
try {
ArrayList <IndexCard> listCards = new ArrayList <> ();
for (HashMap.Entry <String, IndexCard> entry: list.entrySet ()) {
IndexCard card = entry.getValue ();
String name = entry.getValue().name;
if (name.toLowerCase().trim().contains(data.toLowerCase().trim())) {
listCards.add(card);
}
}
return listCards;
} catch (IllegalArgumentException e) {
System.out.println (e + "The indicated data does not appear in the database, you may have entered it incorrectly.");
return null;
}
}
}
All those static methods are what I would put in the new class.
This is how the new class ListAdministrator would look. It would not even need a constructor.
class ListAdministrator{
public static HashMap <String, IndexCard> list = new HashMap <> ();
/**
* Print all the entries of the desired sublist with the ID, Name and phone number.
*/
public static <T extends IndexCard> void SubClasslist (Class <T> subClass) {
for (HashMap.Entry <String, IndexCard> entry: list.entrySet ()) {
String key = entry.getKey ();
IndexCard card = entry.getValue ();
if (card.getClass().equals(subClass)) {
System.out.println ("ID:" + key + "| Name:" + card.name + "| Phone:" + card.phone);
}
}
}
/**
* Returns the object stored in the list of cards when entering the corresponding key.
*/
public static IndexCard GetObjetWithKey(String key) {
try {
return list.get(key);
} catch (IllegalArgumentException e) {
System.out.println (e + ": The indicated key does not appear in the database.");
return null;
}
}
/**
* Obtain the Key when entering the corresponding card.
*/
public static String getKeyWithObject (Object obj) {
for (HashMap.Entry <String, IndexCard> entry: list.entrySet()) {
if (obj.equals(entry.getValue())) {
return entry.getKey();
}
}
throw new IllegalArgumentException ("The indicated data does not appear in the database, and therefore we could not obtain the key.");
}
/**
* Returns a list of cards when entering the main data of the card.
* #param data Corresponds to the identifying name of the file.
*/
public static ArrayList <IndexCard> SearchByName (String data) {
try {
ArrayList <IndexCard> listCards = new ArrayList <> ();
for (HashMap.Entry <String, IndexCard> entry: list.entrySet ()) {
IndexCard card = entry.getValue ();
String name = entry.getValue().name;
if (name.toLowerCase().trim().contains(data.toLowerCase().trim())) {
listCards.add(card);
}
}
return listCards;
} catch (IllegalArgumentException e) {
System.out.println (e + "The indicated data does not appear in the database, you may have entered it incorrectly.");
return null;
}
}
}
You should keep the concerns of managing the IndexCards and the IndexCards themselves separate because of the Single Responsibility Principle. Furthermore the ListAdministrator should handle everything that deals with the management of the IndexCards, also deletion and creation of the managed objects.
The name ListAdministrator is somehow not meeting the point as it does not administrate lists, maybe use something like IndexCardRegistry.
To deal with concurrency you could use a ConcurrentMap as your main data storage.
Having ListAdministrator all static might come in handy if your IndexCards need access to it or other IndexCards, but this would not be the best design. Do they need to know anyway? From my understanding the IndexCards could be simple POJOs that contain only data and no logic at all.
On the other hand with an all-static ListAdministrator you will not be able to use two instances of managed objects at the same time in the future without major refactoring your code. Even if you never would expect this today a well defined object registry that can handle any object might come in handy in projects to come. Therefore I would rather use real instances for the ListAdministrator (and program against it's interface to stay flexible).
In more detail referring to your comments:
The idea of this approach is to keep concerns clearly separated, which will make future changes to your code feasible in case the project grows (most projects tend to do so). My understanding is that the ListAdministrator should manage your IndexCards. In a way this is the same as Object Relational Mappers work, but at the moment your database is a HashMap. If you create an interface for ListAdministrator you may even swap out the HashMap with a database without having to change its clients.
On second investigation of your code I found that IndexCards not only store the data but as well have methods to update the data. This represents another break of the Single Responsibility Principle and should be dealt with. If the ListAdministrator would provide an update method for a given IndexCard it could be used by as many different clients you can think of without changing any code behind the ListAdministrators API. Your first client would be the command-line interface you already have programmed, the next might be a web service.
With an all-static ListAdministrator you have one static Class that manages one static data set. It will always only deal with IndexCards, everything you add will end up in the same HashMap (if allowed/compatible). Every part of your application with access to the class ListAdministrator would have full access to the data. If you needed another ListAdministrator (handling create, delete, update, search) for a different type you would have to refactor everything to accomodate this or start duplicating code. Why not create an instance based solution in the first place. You would have your repository for IndexCards, and could add new repositories at will.
Maybe this is over-engineering for your use case but in keeping the responsibilities clearly separated you will find out that many extensions of your code will happen orthogonal (not affecting existing code), and this is where the fun really begins. And how do you want to practice this if not with smaller projects.
More details about the reason of using interfaces for flexible code (in response to latest comment)
The short answer is: always code against an interface (as stated in numerous articles and java books). But why?
A Java interface is like a contract between a class and its clients. It defines some methods, but does not implement them itself. To implement an interface you define a class with class XYZ implements SomeInterface and the source code of the class does whatever it finds reasonable to answer to the methods defined in the interface. You try to keep the interface small, to contain only the essential methods because the smaller the interface is, the less methods you have to take into account when changes have to be made.
A common idiom in Java would be to define a List<T> return type (the interface) for a method, which most likely would be an ArrayList (concrete class), but could be a LinkedList (another concrete class) as well, or anything else that implements the List interface. By just returning the List interface you prevent your client to use other methods of the otherwise returned concrete class as well which would greatly reduce your freedom to change the internal implementation of your "ListProvider". You hide the internal implementation but agree to return something that fulfills the given interface. If you want to conceed to even less obligations, you could return the interface Iteratable instead of List.
Checkout the Java API, you will find standard classes like ArrayList implement many interfaces. You could always use an ArrayList internally and return it as the smallest interface possible to do the job.
Back to your project. It would be essential to refer to the Registry (ListAdministrator) via its interface, not its concrete class. The interface would define methods like
interface IndexCardRegistry {
void delete(Long id) throws IllegalAccessException;
void update(Long id, Some data) throws IllegalAccessException;
// ...
}
What it does is of no concern for the client, it just hopes everything goes right. So if a client calls the repositories update method it would rely on the repository to update the targeted IndexCard. The repository could store the data as it wants, in a HashMap, in a List or even in a database, it would not matter to the clients.
class IndexCardMapBasedRegistry implements IndexCardRegistry {
private Map store = new HashMap();
void delete(Long id) throws IllegalAccessException {
// code to remove the IndexCard with id from the hashmap
}
void update(Long id, Some data) throws IllegalAccessException {
// code to get the IndexCard with id from
// the hashmap and update its contents
}
// ...
}
Now the new iteration, at creation of your registry you swap out IndexCardMapBasedRegistry for the new
class IndexCardDatabaseRegistry implements IndexCardRegistry {
private Database db;
void delete(Long id) throws IllegalAccessException {
// code to remove the IndexCard with id from the database
}
void update(Long id, Some data) throws IllegalAccessException {
// code to update the IndexCard with id in the database
}
// ...
}
IndexCardRegistry indexCards = new IndexCardMapBasedRegistry(); becomes
IndexCardRegistry indexCards = new IndexCardDatabaseRegistry();
The client must not change at all, but the Registry would be able to handle an amount of IndexCards that otherwise would blow your computers memory.
Stay with IndexCard class and dont need to create new class ListAdministrator
In class IndexCard you have list as of type hashmap and it represent in memory data structure and you have n number of method in this class to work in this data structure so i suggest stay with single class as it will serve single responsibility.

How to flexibly select a single method or class from a long list of sequentially named methods or classes

I know the simple way is to use a switch statement, but that is not what I am asking. I want to know, if I can call a method, based on its name as a String that I can modify from the user's input.
For example, I have a bunch of methods named:
func01
func02
func03
...
I want to call them using a string "func", which I modify by adding a numerical suffix to it, like 01, 02 or 03. I want call them using a few lines of code that will work for any number of methods.
Solution with Reflection
You could use Reflection to call the methods.
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class Main {
public static void main(String args[]) throws Exception {
// Just an example calling all the methods
for (int i = 1; i < 100; i++) {
Object object = invokeMethod("func", i);
if (object != null) {
// Do something with object, cast it, etc. ...
} else {
// Error calling the methods
}
}
}
private static Object invokeMethod(String methodBaseName, int number) {
// Number format will be two digits padded by zeros,
// e.g. 01, 02, ..., 18, ...
// For three digits use "%03d" and so on or calculate
// the digits from the number itself
String methodName = methodBaseName + String.format("%02d", number);
try {
Method methodToInvoke = MethodClass.class.getMethod(methodName);
return methodToInvoke.invoke(new MethodClass());
} catch (NoSuchMethodException | SecurityException
| IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
// Alternatively handle this errors
return null;
}
}
}
class MethodClass {
public Object func01() {
// ...
}
// ...
public Object func99() {
// ...
}
}
Alternatively for static methods, just use:
Method method = MethodClass.class.getMethod(...);
method.invoke(MethodClass.class);
If you want to add parameters, modify the code like this:
getMethod(methodName, parameterType1.class, parameterType2.class, ...);
invoke(..., parameter1, parameter2, ...);
If you want to use a return value, just change the return type from Object to the concrete type and cast the return value from invoke to this type, e.g. Integer:
Integer result = (Integer) method.invoke(...);
Important notice
What you are trying to do is very dangerous. Reflection can be a critical harm for the security of your application. You should never allow a user to input a method name to invoke a method, otherwise he or she could potentially call any method to gain control of your application or memory. Beware of this.
You can do it using reflection. If your method is static, use the code like this:
Method method = ClassName.class.getMethod(name, param1.getClass(), param2.getClass(), ..);
method.invoke(ClassName.class, param1, param2, ..);
Or if your method isn't static, use the code like this:
Method method = object.getClass().getMethod(name, param1.getClass(), param2.getClass(), ..);
method.invoke(object, param1, param2, ..);
Reflection is a dangerous and almost impossible feature to use correctly for new Java programmers. Obtaining a method or other object-oriented element via a string is an antipattern; it breaks type safety, is very difficult to maintain and debug, and will cause you endless bugs. I speak from experience.
Instead, use a single method with overrides for each type of action you want, and let object orientation help you. If you really need a string to tell you which logic flow to use, perhaps an enum will rescue you. You can use the valueOf() method to parse the string into a valid enum, then call the desired functionality through each enum constant's implementation of an abstract method in the enum.
public class Processor
{
FOLD
{
#Override
public void process()
{
// fold logic
}
},
SPINDLE
{
#Override
public void process()
{
// spindle logic
}
},
MUTILATE
{
#Override
public void process()
{
// mutilate logic
}
},
;
abstract public void process();
}
Your client code will be similar to
Processor.valueOf(text).process();
with suitable error checking and exception handling, of course.

Invoke private method with java.lang.invoke.MethodHandle

How can I invoke private method using method handles ?
As far as I can see there are only two kinds of publicly accessible Lookup instances:
MethodHandles.lookup()
MethodHandles.publicLookup()
and neither allows unrestricted private access.
There is the non-public Lookup.IMPL_LOOKUP that does what I want. Is there some public way to obtain it (assuming that SecurityManager allows it) ?
Turns out it's possible with Lookup#unreflect(Method) and temporarily making method accessible (potentially introducing small security issue unless done during program initialization).
Here is modified main method from Thorben's answer:
public static void main(String[] args) {
Lookup lookup = MethodHandles.lookup();
NestedTestClass ntc = new Program().new NestedTestClass();
try {
// Grab method using normal reflection and make it accessible
Method pm = NestedTestClass.class.getDeclaredMethod("gimmeTheAnswer");
pm.setAccessible(true);
// Now convert reflected method into method handle
MethodHandle pmh = lookup.unreflect(pm);
System.out.println("reflection:" + pm.invoke(ntc));
// We can now revoke access to original method
pm.setAccessible(false);
// And yet the method handle still works!
System.out.println("handle:" + pmh.invoke(ntc));
// While reflection is now denied again (throws exception)
System.out.println("reflection:" + pm.invoke(ntc));
} catch (Throwable e) {
e.printStackTrace();
}
}
I don't know, if this is what you really want. Perhaps you could give some more information about what you want to achieve with it.
But if you want to access Lookup.IMPL_LOOKUP, you can do it like in this code sample:
public class Main {
public static void main(String[] args) {
Lookup myLookup = MethodHandles.lookup(); // the Lookup which should be trusted
NestedTestClass ntc = new Main().new NestedTestClass(); // test class instance
try {
Field impl_lookup = Lookup.class.getDeclaredField("IMPL_LOOKUP"); // get the required field via reflections
impl_lookup.setAccessible(true); // set it accessible
Lookup lutrusted = (Lookup) impl_lookup.get(myLookup); // get the value of IMPL_LOOKUP from the Lookup instance and save it in a new Lookup object
// test the trusted Lookup
MethodHandle pmh = lutrusted.findVirtual(NestedTestClass.class, "gimmeTheAnswer", MethodType.methodType(int.class));
System.out.println(pmh.invoke(ntc));
} catch (Throwable e) {
e.printStackTrace();
}
}
// nested class with private method for testing
class NestedTestClass{
#SuppressWarnings("unused")
private int gimmeTheAnswer(){
return 42;
}
}
}
It works with JDK 7, but could break in JDK 8. And be cautious! My antivirus gave an alarm when I executed it.
I think there isn't a public or clean way to do it.
I had a similar issue and finally found a solution: Access non-public (java-native) classes from JDK (7).
Here's a similiar solution which includes arguments in a private
function (I just happened to have the code lying around from a previous project):
class name:
InspectionTree.java
function signature:
private String getSamePackagePathAndName(String className, String classPath)
String firstName = "John";
String lastName = "Smith";
//call the class's constructor to set up the instance, before calling the private function
InspectionTree inspectionTree = new InspectionTree(firstName, lastName);
String privateMethodName ="getSamePackagePathAndName";
Class[] privateMethodArgClasses = new Class[] { String.class, String.class };
Method method =
inspectionTree.getClass().getDeclaredMethod(privateMethodName, privateArgClasses);
method.setAccessible(true);
String className = "Person";
String classPath = "C:\\workspace";
Object[] params = new Object[]{className, classPath};
//note the return type of function 'getSamePackagePathAndName' is a String, so we cast
//the return type here as a string
String answer= (String)method.invoke(inspectionTree, params);
method.setAccessible(false);

Categories