How To Convert String To Runnable Code In Java - 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

Related

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

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.

Java NegativeTest private method with Reflection to catch custom ApplicationException

So I'm testing a AccountService class with a mocked databaselayer.
In this AccountService class there is a private method that checks the input received from UI according to a regex.
The positive test I wrote is working fine:
#Test
public void testEmailPatroonCorrect() throws Exception{
//Correcte emails
List<String> emails = new ArrayList<>();
emails.add("user#domain.com");
emails.add("user#domain.co.in");
emails.add("user.name#domain.com");
emails.add("user_name#domain.com");
emails.add("username#yahoo.corporate.in");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
assertThatCode(() -> {
for(String email : emails){
method.invoke(AccountService,email);
}}).doesNotThrowAnyException();
}
However for the negative test (a list with wrong email patterns) even with only one object in the list for simplicity
#Test
public void testEmailPatroonFout() throws Exception{
//Verkeerde emailpatronen
List<String> emails = new ArrayList<>();
emails.add(".username#yahoo.com");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
assertThatThrownBy(()->{
for(String email : emails){
method.invoke(AccountService,email);
}
}).isInstanceOf(ApplicationException.class).hasMessage(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg());
}
The exception thrown during test is: java.lang.reflect.InvocationTargetException. In the application the ApplicationException gets caught just fine.
Question is how can I write a proper test for a list of wrong email patterns? (without using #VisibleForTesting functionality since it's a school project).
Many thanks!
The InvocationTargetException wraps the exception thrown within the reflectively invoked method. So you may catch the InvocationTargetException and rethrow its cause, but I’d put that into a utility method, like
public interface TestMethod<D,A> {
void invoke(D d, A a) throws Throwable;
}
static <D,A> TestMethod<D,A> method(
Class<D> declarer, String name, Class<A> argType) throws ReflectiveOperationException {
Method method = declarer.getDeclaredMethod(name, argType);
method.setAccessible(true);
return (d,a) -> {
try {
method.invoke(d, a);
} catch(InvocationTargetException ex) {
throw ex.getTargetException();
}
};
}
which you can use like
#Test
public void testEmailPatroonFout() throws Exception{
//Verkeerde emailpatronen
List<String> emails = new ArrayList<>();
emails.add(".username#yahoo.com");
TestMethod<AccountService, String> method
= method(AccountService.class, "checkEmailPatroon", String.class);
assertThatThrownBy(() -> {
for(String email : emails){
method.invoke(AccountService, email);
}
}).isInstanceOf(ApplicationException.class)
.hasMessage(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg());
}
The shape of the TestMethod interface allows the alternative implementation like
static <D,A> TestMethod<D,A> method(
Class<D> declarer, String name, Class<A> argType) throws ReflectiveOperationException {
Method method = declarer.getDeclaredMethod(name, argType);
method.setAccessible(true);
return MethodHandleProxies.asInterfaceInstance(
TestMethod.class, MethodHandles.lookup().unreflect(method));
}
Thanks to Holger I was able to write a working test for it's purpose.
#Test
public void testEmailPatroonFoutLoop() throws Throwable {
//Verkeerde emailpatronen
List<String> wrongEmails = new ArrayList<>();
wrongEmails.add(".username#yahoo.com");
wrongEmails.add("username#yahoo.com.");
wrongEmails.add("usernameyahoo.com");
wrongEmails.add("username#yahoo.c");
wrongEmails.add("use..rname#yahoo.com");
Class<AccountService> foo = AccountService.class;
Method method = foo.getDeclaredMethod("checkEmailPatroon", String.class);
method.setAccessible(true);
int countedWrongEmails = 0;
for(String email : wrongEmails){
try{
method.invoke(accServ,email);
}
catch (InvocationTargetException ie){
Exception e = (Exception) ie.getTargetException();
if(e.getMessage().equals(ApplicationExceptionType.ONGELDIGE_EMAIL.getMsg())){
countedWrongEmails++;
}
}
}
assertThat(countedWrongEmails).isEqualTo(wrongEmails.size());
}
Although I see the benefits and elegance of writing a TestMethod interface, I however do not yet possess the knowledge to grasp it's complexity. So I will stick to this test that I'll be able to explain on the verbal exam.

Javassist - Remove static modifier from method

I'm writing some Javassist code to intercept method calls and replace them with a proxy. To do that I'm using ExprEditor to replace the call in the following manner:
public static void main(String[] args) {
try {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass = pool.get("Test");
CtMethod meth = ctClass.getDeclaredMethod("main");
meth.instrument(new ExprEditor() {
#Override
public void edit(final MethodCall m) throws CannotCompileException {
try {
if (m.getClassName().contains("Functions")) {
/* MAKE NON STATIC
CtClass old = pool.get(m.getClassName());
m.getMethod().setModifiers(Modifier.PUBLIC);
old.toClass();
*/
String s = m.getClassName() + " proxy = (" +
m.getClassName() + ") " + Main.class.getName() + ".create(" + m.getClassName() + ".class);" +
" $_ = proxy." + m.getMethodName() + "($$);";
m.replace(s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
Class clazz = ctClass.toClass();
Method method = clazz.getMethod("main", String[].class);
method.invoke(null, new Object[]{new String[]{}});
} catch (InvocationTargetException e) {
e.getCause().printStackTrace();
} catch (NoSuchMethodException | IllegalAccessException | NotFoundException | CannotCompileException e) {
e.printStackTrace();
}
}
This works as desired as long as the method isn't static. Now I'm trying to change static methods to non static through the use of the commented code.
It seems to me that this should work and there are similar usages in the Javassist docs for other modifiers, but when I uncomment and run it I get the following error message:
javassist.CannotCompileException: by java.lang.ClassFormatError: Arguments can't fit into locals in class file Functions/Color
I've also tried to remove the static modifier instead of just setting modifiers to public as such
m.getMethod().setModifiers(m.getMethod().getModifiers() & ~Modifier.STATIC);
But the problem remains.
Is this actually possible?
So you are trying to remove a static modifier from a reserved entry point method name "main" in class Test. I think the compiler won't let you do that, because main is a reserved method name and can only have one predefined signature. And also, static methods are problematic; when called from within the class, if you remove the static modifier, all calls to them would also cause a compilation error, because they were not ment to be instance methods in original code.

JAVA creating an event list from a text file

I have a controller class, it basically holds an event list.
ArrayList <Event> eventList = new ArrayList<>();
The controller has an addEvent(Event e) method.
I've extended the controller class to be a specific kind of controller, and extended event to provide specific kinds of events for my new controller as inner classes.
public class NewController extends Controller{
//.. controller code/methods
class SpecificEvent extends Event{
//..
}
}
I've hard coded my controller to work as I intended, but I wanted to be able to make a configuration file that would populate my event list.
I made a .txt file with a list of events:
Event=SpecificEvent, Arg1=<Integer>val, .. ArgN=<?>val, Event=SpecificEventN, ArgN=<?>val
I filtered out the event class name and arguments into a list:
fileContents.stream()
.forEach(s -> {
Scanner sc = new Scanner(s)
.useDelimiter("=|,");
while (sc.hasNext()){
Scanner sc2 = new Scanner(sc.next()).useDelimiter("[//w]");
args.add(sc.next());
}
});
My problem is that events have different constructor argument types and lengths; I don't know how to build them from my file. I'm new to this kind of work and I figure this is run of the mill implementation.
Do I use the Reflect package? Please help. I was thinking off an Event Factory?
Thanks for the community help. This factory will do the job when provided a string array argument, {String classname, args.... }
/**
* ClassFactory method, build an event.
*
* #param arguments Required arguments to build an Event.
* #return Built event.
* #throws java.lang.ClassNotFoundException
*/
public Event buildEvent(String [] arguments) throws ClassNotFoundException {
Class<?>[] argumentTypes = {};
Object[] parameters = {};
try {
//define the class type from the first argument
Class<?> eventClass
= Class.forName(packageName + arguments[0]);
if (arguments.length() > 1) {
argumentTypes = new Class<?>[]{Long.TYPE};
parameters = new Object[]{Long.parseLong(arguments[1])};
Constructor<?> constructor
= eventClass.getDeclaredConstructor(argumentTypes);
Object instance = constructor.newInstance(parameters);
return ((Event) instance);
//default
} else {
Constructor<?> constructor
= eventClass.getDeclaredConstructor();
Object instance = constructor.newInstance();
return ((Event) instance);
}
} catch (ClassNotFoundException cnfe) {
System.out.println("Class not available in this package.");
} catch (NoSuchMethodException |
SecurityException |
InstantiationException |
IllegalAccessException |
IllegalArgumentException |
InvocationTargetException e) {
log.log(Level.SEVERE, "Class Builder: {0}", e.getMessage());
}
return null;
}

How to access the status of the printer?

I need to know the Printer Status. I need to control the Printer Status using Java Program.
Example
Check the Printer status, weather will it accept the Job or not,
Out of Paper
Printer queue
Toner
and etc..
I know there is a way to check the basic information, such as name, color supported or not. But I can't find any example to check paper, toner, job queue. I like to know if it is possible to using Java API. I found big API for printer function, but they didn't give a simple example how to use it.
Have a look at this PrinterStateReason. And also javax.print.
Getting the complete status of a printer is not possible. Printers have a native driver which is able to request services but because there are so many possible printer functionalities, Java only supports a subset of it.
You can actually offer the user to modify the status by calling
PrinterJob pj = PrinterJob.getPrinterJob();
pj.printDialog()
which shows the native printer dialog.
Despite the information in the javax.print API that it is possible to check the printer state, I was not able to do so for my printer !. (Canon).
Code to check:
import javax.print.*;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.PrintServiceAttributeSet;
import javax.print.attribute.standard.PrinterStateReason;
import javax.print.attribute.standard.PrinterStateReasons;
import javax.print.attribute.standard.Severity;
import javax.print.event.*;
import java.awt.*;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.*;
import java.util.Set;
/**
* PrintTest
*/
public class PrintTest implements PrintServiceAttributeListener,PrintJobListener,Doc, Printable, PrintJobAttributeListener {
private static final transient String TEXT = "12345";
public static void main(String[] args) {
PrintTest test = new PrintTest();
test.checkPrinters();
}
public void checkPrinters() {
Thread newThread = new Thread(new Runnable() {
public void run() {
PrintService ps = PrinterJob.getPrinterJob().getPrintService();
DocFlavor[] myFlavors = ps.getSupportedDocFlavors();
ps.addPrintServiceAttributeListener(PrintTest.this);
DocPrintJob docJob = ps.createPrintJob();
docJob.addPrintJobAttributeListener(PrintTest.this, null);
docJob.addPrintJobListener(PrintTest.this);
try {
docJob.print(PrintTest.this,null);
}
catch (PrintException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
} });
newThread.start();
/**
PrintServiceAttributeSet attSet = ps.getAttributes();
PrinterStateReasons psr = ps.getAttribute(PrinterStateReasons.class);
if (psr != null) {
Set<PrinterStateReason> errors = psr.printerStateReasonSet(Severity.REPORT);
for (PrinterStateReason reason : errors)
System.out.printf(" Reason : %s",reason.getName());
System.out.println();
} */
}
public void attributeUpdate(PrintServiceAttributeEvent psae) {
System.out.println(psae.getAttributes());
}
public void printDataTransferCompleted(PrintJobEvent pje) {
System.out.println("Transfer completed");
}
public void printJobCompleted(PrintJobEvent pje) {
System.out.println("Completed");
}
public void printJobFailed(PrintJobEvent pje) {
System.out.println("Failed");
PrinterStateReasons psr = pje.getPrintJob().getPrintService().getAttribute(PrinterStateReasons.class);
if (psr != null) {
Set<PrinterStateReason> errors = psr.printerStateReasonSet(Severity.REPORT);
for (PrinterStateReason reason : errors)
System.out.printf(" Reason : %s",reason.getName());
System.out.println();
}
}
public void printJobCanceled(PrintJobEvent pje) {
System.out.println("Canceled");
}
public void printJobNoMoreEvents(PrintJobEvent pje) {
System.out.println("No more events");
}
public void printJobRequiresAttention(PrintJobEvent pje) {
System.out.println("Job requires attention");
PrinterStateReasons psr = pje.getPrintJob().getPrintService().getAttribute(PrinterStateReasons.class);
if (psr != null) {
Set<PrinterStateReason> errors = psr.printerStateReasonSet(Severity.REPORT);
for (PrinterStateReason reason : errors)
System.out.printf(" Reason : %s",reason.getName());
System.out.println();
}
}
public DocFlavor getDocFlavor() {
return DocFlavor.SERVICE_FORMATTED.PRINTABLE; //To change body of implemented methods use File | Settings | File Templates.
}
public Object getPrintData() throws IOException {
return this;
}
public DocAttributeSet getAttributes() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Reader getReaderForText() throws IOException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public InputStream getStreamForBytes() throws IOException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
return pageIndex == 0 ? PAGE_EXISTS : NO_SUCH_PAGE; //To change body of implemented methods use File | Settings | File Templates.
}
public void attributeUpdate(PrintJobAttributeEvent pjae) {
System.out.println("Look out");
}
}
I have tried to get a PrinterReasonsState by willfully opening the case or removing the paper, but I was unsuccessfull. Perhaps someone else can show how it is possible, but so far it seems that the API offers much more functionality which is in reality not available.
Or in short:
It does not work, at least not for my printer.
I was told one could check the printer status this way:
PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
AttributeSet attributes = printService.getAttributes();
String printerState = attributes.get(PrinterState.class).toString();
String printerStateReason = attributes.get(PrinterStateReason.class).toString();
System.out.println("printerState = " + printerState); // May be IDLE, PROCESSING, STOPPED or UNKNOWN
System.out.println("printerStateReason = " + printerStateReason); // If your printer state returns STOPPED, for example, you can identify the reason
if (printerState.equals(PrinterState.STOPPED.toString()) {
if (printerStateReason.equals(PrinterStateReason.TONER_LOW.toString()) {
System.out.println("Toner level is low.");
}
}
Sadly it seems that my printer doesn't have support for printerState so I can't test it.
UPDATE:
Instead of querying WMI "win32_printer" object I would recommend using Powershell directly like this, its much cleaner API :
Get-Printer | where PrinterStatus -like 'Normal' | fl
To see all the printers and statuses:
Get-Printer | fl Name, PrinterStatus
To see all the attributes:
Get-Printer | fl
You can still use ProcessBuilder in Java as described below.
Before update:
Solution for Windows only.
In Windows you can query WMI "win32_printer" class, so you check that the state on OS layer: Win32_Printer class
In Java you can use ProcessBuilder like this to start PowerShell and execute the PS script like this:
String printerName = "POS_PRINTER";
ProcessBuilder builder = new ProcessBuilder("powershell.exe", "get-wmiobject -class win32_printer | Select-Object Name, PrinterState, PrinterStatus | where {$_.Name -eq '"+printerName+"'}");
String fullStatus = null;
Process reg;
builder.redirectErrorStream(true);
try {
reg = builder.start();
fullStatus = getStringFromInputStream(reg.getInputStream());
reg.destroy();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.print(fullStatus);
After converting the InputStream to String you should get something like that:
Name PrinterState PrinterStatus
---- ------------ -------------
POS_PRINTER 0 3
State and Status should change for various situations (printer turned off, out of paper, cover opened,...).
This should work, but depends on the printer and drivers. I used this with EPSON TM printers with ESDPRT port and I could get information like: no paper, cover open, printer offline/turned off, printer paused.
More comprehensive answer here:
- my StackOverflow answer on a similar question.

Categories

Resources