How would I access this variable from outside of this method? - java

I've been attempting to develop a Minecraft mod, but have hit a road block in which I have had no luck in surpassing. In my attempts to find a fix for this issue, I have sifted through multiple other questions and websites, but to no avail.
The closest I have gotten would be where I created the variable outside of the method and then set the value inside of the method. But, the issue with this is that it would always return with null.
Also, if it was not clear, I am talking about the "taskEntriesMethod" variable.
Here's my code:
public void getExecutingTaskEntries(Profiler profiler)
{
try
{
Class<?> AITasks = Class.forName("net.minecraft.entity.ai.EntityAITasks");
Field taskEntries = AITasks.getDeclaredField("executingTaskEntries");
taskEntries.setAccessible(true);
Object AITasksObj = taskEntries.get(new EntityAITasks(profiler));
Set<EntityAITasks.EntityAITaskEntry> taskEntriesMethod = (Set<EntityAITaskEntry>) AITasksObj;
}
catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException exception) { exception.printStackTrace(); }
}
private final Set<EntityAITasks.EntityAITaskEntry> executingTaskEntries = taskEntriesMethod; // <-- (this is what errors out)

You've created a get method but have declared it as a void. You probably want to change your code to something like this:
public Set<EntityAITasks.EntityAITaskEntry> getExecutingTaskEntries(Profiler profiler) {
//your code
return (Set<EntityAITaskEntry>) AITasksObj;
}
And then use it like so
Set<EntityAITasks.EntityAITaskEntry> executingTaskEntries = getExecutingTaskEntries(profiler)

Do you need executingTaskEntries to be final?
You could simply:
public void initExecutingTaskEntries(Profiler profiler) // changed name here, get suggested its going to return something
{
try
{
Class<?> AITasks = Class.forName("net.minecraft.entity.ai.EntityAITasks");
Field taskEntries = AITasks.getDeclaredField("executingTaskEntries");
taskEntries.setAccessible(true);
Object AITasksObj = taskEntries.get(new EntityAITasks(profiler));
executingTaskEntries = (Set<EntityAITaskEntry>) AITasksObj;
}
catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException exception) { exception.printStackTrace(); }
}
private Set<EntityAITasks.EntityAITaskEntry> executingTaskEntries;
if you need executingTaskEntries to be final then I would initialize it as empty Set and then just add entires to it within your method.

Related

How To Convert String To Runnable Code In Java

I Have Java code stored as a string in a database. For example:
String x = "System.out.println(\"X\")";
I need to convert it into java.lang.Runnable to run it in task executor service. How Can I create it ?
private Runnable StringToRunnable(String task){
Runnable runnable = null;
return runnable;
}
Janino is a popular choice for an on-demand-compiler. It's being used by many open source projects.
The usage is straight forward. The code
import org.codehaus.janino.ScriptEvaluator;
public class App {
public static void main(String[] args) throws Exception {
String x = "System.out.println(\"X\");"; //<-- dont forget the ; in the string here
ScriptEvaluator se = new ScriptEvaluator();
se.cook(x);
se.evaluate(new Object[0]);
}
}
prints x.
As others have already pointed out, loading code from the database and executing it might be a bit risky.
I Created This Method
private void getMethod(String fromClass, String fromMethod) {
Class<?> aClass;
try {
aClass = Class.forName(fromClass);
Method method = aClass.getMethod(fromMethod);
method.setAccessible(true);
method.invoke(aClass.newInstance());
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
e.printStackTrace();
}
}
and called it by
Runnable task = () -> getMethod(fromClass, fromMethod);
and i put className and method Name in database by :
this.getClass().getCanonicalName() and string method name

Instantiate and use an object with only the textual class name in Java

I have several classes in the same package in Java. I want to instantiate objects of these classes from an array that has the class names as strings.
Here is an example of a class I would like to use, they all have the same structure.
class Class1 {
public String[] firstMethod(){
String[] data = {"NEW_ITEM"};
return data;
}
}
Here is the class I am attemtempting to instantiate them from.
class Main {
static {
String[] classes = {"Class1","Class2"};
for (String cls : classes) {
try {
Object o = Class.forName(cls).newInstance();
o.firstMethod();
} catch(ClassNotFoundException | IllegalAccessException | InstantiationException ex) {
System.out.println(ex.toString());
}
}
My problem is that when I try to call firstMethod() using the object o, I am getting this error.
exit status 1
Main.java:19: error: cannot find symbol
o.firstMethod();
^
symbol: method firstMethod()
location: variable o of type Object
1 error
I suspect that it is because it is of type Object and not type Class1. I have seen solutions where you typecast the object to the object of the class that you need. However when you typcast, you need to use the name of the class, which is exactly what I am trying to avoid. I need to use the class name as a string.
Does anyone know of a solution where I can call methods with the objects that are created?
You can't call your method the way in your code because you have an object which does not know the type Class1. You need to cast it explicitly like
((Class1)o).firstMethod()
which I don't think this is what you want.
Or, you can iterate through object methods and invoke it dynamically like below:
String[] classes = {"com.yourpackage.Class1", "com.yourpackage.Class2"};
for (String cls : classes) {
try {
Object o = Class.forName(cls).newInstance();
for(Method m : o.getClass().getMethods()) {
System.out.println(m.getName());
if ("firstMethod".equals(m.getName())) {
String[] data = (String[])m.invoke(o, null); // here are the parameters
for(String d : data){
System.out.println(d);
}
}
}
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException ex) {
System.out.println(ex.toString());
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
The output is :
NEW_ITEM

Typecasting with a class that is protected

I am trying to override some class of vertx web project, since I have to change some of the features. So the tricky part comes here.
#Override
public void reroute(HttpMethod method, String path) {
int split = path.indexOf('?');
if (split == -1) {
split = path.indexOf('#');
}
if (split != -1) {
log.warn("Non path segment is not considered: " + path.substring(split));
// reroute is path based so we trim out the non url path parts
path = path.substring(0, split);
}
/*((HttpServerRequestWrapper) request).setMethod(method);
((HttpServerRequestWrapper) request).setPath(path);*/
((HttpServerRequestWrapper) request).setMethod(method);
((HttpServerRequestWrapper) request).setPath(path);
request.params().clear();
// we need to reset the normalized path
normalisedPath = null;
// we also need to reset any previous status
statusCode = -1;
// we need to reset any response headers
response().headers().clear();
// special header case cookies are parsed and cached
if (cookies != null) {
cookies.clear();
}
// reset the end handlers
if (headersEndHandlers != null) {
headersEndHandlers.clear();
}
if (bodyEndHandlers != null) {
bodyEndHandlers.clear();
}
failure = null;
restart();
}
This code throws me a compilation error saying:
'HttpServerRequestWrapper cannot be accessed from outside package'
I know for a fact that we can use reflection to create objects of a class that cannot be accessed. Can reflection be used in this case? How can I fix such an issue.
Any help will be much appreciated.
In java 8 and/or without modules it is possible to just place class like that in same package as original one to get access to all package-default classes.
Otherwise you need to use reflections like in other response, but I would add that it is good idea to cache that Class and Method instance, as using Class.forName and clazz.getDeclaredMethod each time will slowdown code.
What about getting the Class object and then calling the methods on your specific (uncasted) object?
I assume request is a class attribute of type HttpServerRequestWrapper. Then, this is what I suggest:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
...
private final Method setMethod;
private final Method setPath;
public MyConstructor() {
Method tmp1 = null, tmp2 = null;
try {
final Class<?> clazz = Class.forName("io.vertx.ext.web.impl.HttpServerRequestWrapper");
tmp1 = clazz.getMethod("setMethod", HttpMethod.class);
tmp1.setAccessible(true);
tmp2 = clazz.getMethod("setPath", String.class);
tmp2.setAccessible(true);
} catch (ClassNotFoundException e) {
// do something
} catch (NoSuchMethodException e) {
// do something
} catch (SecurityException e) {
// do something
}
this.setMethod = tmp1;
this.setPath = tmp2;
}
...
#Override
public void reroute(HttpMethod method, String path) {
...
try {
this.setMethod.invoke(request, method);
this.setPath.invoke(request, path);
} catch (IllegalAccessException e) {
// do something
} catch (IllegalArgumentException e) {
// do something
} catch (InvocationTargetException e) {
// do something
}
...
}
EDIT: I updated this answer based on #GotoFinal's suggestion.
It looks like HttpServerRequestWrapper implements HttpServerRequest. So, you can change "HttpServerRequestWrapper" to "HttpServerRequest" in your code. But remember that by doing so, you'll only be able to call methods specified in the interface.
You can see those methods in https://vertx.io/docs/apidocs/io/vertx/rxjava/core/http/HttpServerRequest.html.

How to not catch a particular line exception in try catch box in JAVA?

Here is my code:
whatever exception it throws I don't want to catch it outside, I want to continue my loop again by handling it separately. I don't want to use another try catch inside this try catch. Can someone guide me on this?
I don't want to use another try catch inside this try catch.
Yes you do.
MarketplaceBO marketplaceBOObject = new MarketplaceBO(entity.getMarketplaceID());
try {
marketplaceBOObject.loadFromSable();
} catch (WhateverException e) {
// Do something here, or, if you prefer, add the exception to a list and process later
doSomething() ;
// Continue your loop above
continue ;
}
if (marketplaceBOObject.isActive()) {
If you REALLY don't want to do this, your loadFromSable() method could return some object that provides information about success/failure of the call. But I wouldn't recommend that.
do this way -- this way your rest of the code will run no matter there is an exception or not
for (MerchantMarketplaceBO entity : merchantMarketplaceBOList) {
MarketplaceBO marketplaceBOObject = new MarketplaceBO(entity.getMarketplaceID());
try{
marketplaceBOObject.loadFromSable();
if (marketplaceBOObject.isActive()) {
resultVector.add(marketplaceBOObject.getCodigoMarketplace());
}
}
catch{
if (marketplaceBOObject.isActive()) {
resultVector.add(marketplaceBOObject.getCodigoMarketplace());
}
}
}
Another "trick" to deal with that is to move the body to the loop into a separate method having the "additional" try/catch block:
private MarketplaceBO loadFromSable(MerchantMarketplaceBO entity){
MarketplaceBO marketplaceBOObject = new MarketplaceBO(entity.getMarketplaceID());
try {
marketplaceBOObject.loadFromSable();
} catch (WhateverException e) {
// do something to make marketplaceBOObject a valid object
// or at least log the exception
}
return marketplaceBOObject;
}
But since we want to stick to the Same Layer of Abstraction principle we also need to move other part of that method to new smaller methods:
public void serveFromSableV2() {
String merchantCustomerID = ObfuscatedId.construct(request.getMerchantCustomerID()).getPublicEntityId();
try {
List<MerchantMarketplaceBO> merchantMarketplaceBOList =
getAllMerchantMarketplacesBOsByMerchant();
Vector<Marketplace> resultVector = new Vector<>();
for (MerchantMarketplaceBO entity : merchantMarketplaceBOList) {
MarketplaceBO marketplaceBOObject = loadFromSable(entity);
addToActiveMarketplacesList(marketplaceBOObject,resultVector);
}
verifyHavingActiveMarketPlaces(resultVector);
setResponseWithWrapped(resultVector);
} catch (EntityNotFoundException | SignatureMismatchException | InvalidIDException e) {
throw new InvalidIDException("merch=" + merchantCustomerID + "[" + request.getMerchantCustomerID() + "]"); //C++ stack throws InvalidIDException if marketplace is not found in datastore
}
}
You could refactor the load into a separate method that catches and returns the exception instead of throwing it:
private Optional<Exception> tryLoadFromSable(MarketplaceBO marketplaceBOObject) {
try {
marketplaceBOObject.loadFromSable();
return Optional.empty();
}
catch(Exception e) {
return Optional.of(e);
}
}
Then inside your loop:
//inside for loop...
MarketplaceBO marketplaceBOObject = new MarketplaceBO(entity.getMarketplaceID());
Optional<Exception> loadException = tryLoadFromSable(marketplaceBOObject);
if(loadException.isPresent()) {
//Do something here, log it, save it in a list for later processing, etc.
}

Unhandled exception type NoSuchFieldException (java reflection)

I am using Play Framework about 1 month and it is a great thing, but I had one big problem
.
I`ve try to run following code in secure controller:
MyModel myModel = MyModel.all().first();
Field idField = myModel.getClass().getField("id");
About line 2 Play says:
Compilation error
The file /app/controllers/Security.java could not be compiled. Error
raised is : Unhandled exception type NoSuchFieldException
Maybe it`s a core bug?
Thanks.
You should handle the exception that getField(String fieldName) can throw. In this case a NoSuchFieldException.
Try to write it as such:
Field idField = null;
try {
idField = myModel.getClass().getField("id");
} catch (NoSuchFieldException nsfe) {
throw new RuntimeException(nsfe);
}
If you use dp4j's #TestPrivates or #Reflect(catchExceptions =true) you don't need to write the catch statements yourself:
public class Security{
#Reflect(catchExceptions =true) //when false it will add the exceptions to the throws list.
public void aMethod(){
MyModel myModel = MyModel.all().first();
Field idField = myModel.getClass().getField("id");
//you might as well write:
// int id = myModel.id;
}

Categories

Resources