I am trying to use reflection to launch the appropriate method when the user inputs a string command. For instance, if the user inputs "go" in the terminal, the go() method of the Player class will be called by the process() method of the Command class.
However, I cannot get my code working and I get a NoSuchMethodException error that I do not know how to fix. The lines at the source of the problem are half-way through the Command class (complete classes reproduced at the bottom):
try {
Method method = pClass.getMethod(commandWord);
method.invoke(player, this);
}
catch (NoSuchMethodException err1) {
System.out.println("No such method");
}
Could anyone please guide me? I thank you in advance.
LC
Command class:
import java.util.ArrayList;
import java.lang.reflect.*;
public class Command
{
private String commandWord;
private String secondWord;
public Command(String firstWord, String secondWord)
{
commandWord = firstWord;
this.secondWord = secondWord;
}
public boolean process(Player player)
{
ArrayList<String> validCommands = new ArrayList<String>();
String methodName;
int index;
Class pClass = player.getClass();
Method[] methods = pClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
if (Modifier.isPublic(methods[i].getModifiers())) {
validCommands.add(methods[i].getName());
}
}
boolean wantToQuit = false;
if(commandWord == null) {
System.out.println("I don't know what you mean...");
return false;
}
if (commandWord.equals("help")) {
System.out.println("You are lost. You are alone. You wander");
System.out.println("around at the university.");
System.out.println();
System.out.println("Your command words are:");
for(String command: validCommands) {
System.out.print(command + " ");
}
System.out.println();
}
else if (commandWord.equals("quit")) {
wantToQuit = quit();
}
//THIS IS WHERE I GET THE ERROR
try {
Method method = pClass.getMethod(commandWord);
method.invoke(player, this);
}
catch (NoSuchMethodException err1) {
System.out.println("No such method");
}
catch (IllegalAccessException err2) {
System.out.println("Illegal access");
}
catch (InvocationTargetException err3) {
System.out.println("Illegal access");
}
return wantToQuit;
}
[...] //some methods omitted
}
Player class:
public class Player
{
private String name;
private Room currentRoom;
private ArrayList<Item> items;
Player (String name, Room startingRoom)
{
this.name = name;
items = new ArrayList<Item>();
this.currentRoom = startingRoom;
printWelcome();
}
public void engage()
{
[...]
}
public void trade(Command command)
{
[...] }
public void goRoom(Command command)
{
[...] }
public void search(Command command)
{
[...] }
public void takeItem(Command command)
{
[...] }
public void dropItem(Command command)
{
[...] }
public void lock(Command command)
{
[...] }
public void unlock(Command command)
{
[...]
}
}
Try this.
pClass.getMethod(commandWord, Command.class)
Seems to me the problem is that you're looking for methods with no
parameters while these methods all seem to have a parameter of type Command.
For more details see here:
Class.getMethod JavaDoc
Related
I have 10 Ids in List, and 6 methods.I need to every id in 6 methods.
Example:
//passsing 1st id in all 6 methods, these 6 methods should run parallel
getBook1(1);
getBook2(1);
getBook3(1);
getBook4(1);
getBook5(1);
getBook6(1);
// passing 2nd id in all 6 methods
getBook1(2);
getBook2(2);
getBook3(2);
getBook4(2);
getBook5(2);
getBook6(2);
.
.
.
// passing 10th id in all 6 methods
getBook1(10);
getBook2(10);
getBook3(10);
getBook4(10);
getBook5(10);
getBook6(10);
When i pass the 2nd id in all 6 methods, in parallel 1 id methods should also run in parallel.
Like for all these 10 ids for 6 methods should run parallel in java.
Please help me with solution.
Thanks for your response. please check the updated code below.
public class TestClass {
DataSource ds = null;
Connection mysqlcon = null;
PreparedStatement mysqlstmt = null;
ResultSet mysqlrs=null;
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
TestClass tc = new TestClass();
List<String> idsList = tc.getIpadds();
ExecutorService executorService = Executors.newFixedThreadPool(idsList .size());
Method[] methods = TestClass.class.getMethods();
for (String id : idsList ) {
callbookMethod(executorService,id,methods);
}
}
private List<String> getIpadds() {
List<String> ipadds = new ArrayList<String>();
try {
// MySql Dash Board Connection
ds = MyDataSourceFactory.getDashBoardMySQLDataSource();
mysqlcon = ds.getConnection();
String sql="SELECT DISTINCT IPADD FROM atm_master_copy_3";
mysqlstmt = mysqlcon.prepareStatement(sql);
ResultSet mysqlrs =mysqlstmt.executeQuery();
while(mysqlrs.next()) {
ipadds.add(mysqlrs.getString(1));
}
}catch(SQLException e) {
e.printStackTrace();
}finally {
if(mysqlcon != null) {
try {
mysqlcon.close();
}catch(SQLException e) {
e.printStackTrace();
}
mysqlcon = null;
}
}
return ipadds;
}
public static void callbookMethod (ExecutorService executorService,final String id, final Method[] methods){
final TestClass testClass = new TestClass();
executorService.execute(new Runnable() {
#Override
public void run() {
for (Method method : methods) {
try {
String methodName = method.getName();
if (methodName.startsWith("update")) {
method.invoke(testClass,id);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
public void updateCMaster(String id) {
System.out.println("updateCMaster");
}
public void updateFMaster(String id) {
// Do Something
System.out.println("updateFMaster");
}
public void updateASMaster(int id) {
// Do Something
System.out.println("updateASMaster");
}
}
i am geting 250 ids in list.
Here you go this will do what you asked for, but this is not a good idea since you will kill your machine because if the list size is big:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestClass {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
int[] idsList = {1,2,3,4,5,6,7,8,9,10};
ExecutorService executorService = Executors.newFixedThreadPool(idsList.length);
Method[] methods = TestClass.class.getMethods();
for (int id : idsList) {
callbookMethod(executorService,id,methods);
}
}
public static void callbookMethod (ExecutorService executorService,int id, Method[] methods){
TestClass testClass = new TestClass();
executorService.execute(new Runnable() {
#Override
public void run() {
for (Method method : methods) {
try {
String methodName = method.getName();
if (methodName.startsWith("getBook")) {
method. invoke(testClass,id);
}
// method.invoke(id);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}
public void getBook1(int id) {
// Do Something
System.out.println("Book 1:");
}
public void getBook2(int id) {
// Do Something
System.out.println("Book 2:");
}
public void getBook3(int id) {
// Do Something
System.out.println("Book 3:");
}
public void getBook4(int id) {
// Do Something
System.out.println("Book 4:");
}
public void getBook5(int id) {
// Do Something
System.out.println("Book 5:");
}
public void getBook6(int id) {
// Do Something
System.out.println("Book 6:");
}
}
I am trying to implement the observer pattern to a game i have made. When a villain is created in the battle-zone file using threads, I would like to use the observer pattern to create a hero using threads and add it to the same file. The villians and heroes are created using the factory method pattern. I am unsure of where to go with regards to linking my HeroCreationMain class to the observer pattern classes.
Villian Creation
public class VillianCreationMain {
private static Villian villian;
public static void main(String[] args, int userInput) throws IOException {
String fileName = null;
Random randomVillian = new Random();
int amountOfVillians = userInput;
if (amountOfVillians < 7) {
for (int x = 0; x < amountOfVillians; x++) {
int randomGenerator = randomVillian.nextInt(6);
for (int i = 0; i < 5; i++) {
if (randomGenerator == 0 ) {
setVillian(new FlyingVillian());
}
else if (randomGenerator == 1) {
setVillian(new StrongVillian());
}
else if (randomGenerator == 2) {
setVillian(new FastVillian());
}
else if (randomGenerator == 3) {
setVillian(new SmartVillian());
}
else if (randomGenerator == 4) {
setVillian(new FireVillian());
}
else if (randomGenerator == 5) {
setVillian(new IceVillian());
}
try {
writeToFile(getVillian(), i, fileName);
}
catch (IOException e) {
System.out.println(e.getMessage());
}
}
VillianThreads t1 = new VillianThreads(VillianCreationMain.getVillian());
t1.start();
}
}
else {
System.out.println("Please enter a value of less than 7");
}
}
public static void writeToFile(Villian villian, int amountOfVillians, String fileName) throws IOException {
for(int x = 0; x < amountOfVillians; x++) {
// String parsedInt = Integer.toString(x);
fileName = "battle-zone.ser";
FileOutputStream file = new FileOutputStream(fileName);
ObjectOutputStream oos = new ObjectOutputStream(file);
oos.writeObject(villian);
file.close();
oos.close();
}
}
public static Villian getVillian() {
return villian;
}
public static void setVillian(Villian villian) {
VillianCreationMain.villian = villian;
}
}
Hero Creation
public class HeroCreationMain {
private static Hero hero = null;
public static void main(String[] Hero) {
EnemyStatus enemyStatus = new EnemyStatus();
VillianObserver observer1 = new VillianObserver(enemyStatus);
}
public static void readFile() throws IOException, ClassNotFoundException {
#SuppressWarnings("resource")
ObjectInputStream ois = new ObjectInputStream (new FileInputStream("battle-zone.ser"));
Villian targetVillian = (Villian) ois.readObject();
System.out.println(targetVillian + " is being attacked by a hero!");
}
public static Hero getHero() {
return hero;
}
public static void setHero(Hero hero) {
HeroCreationMain.hero = hero;
}
}
Observer
public interface Observer {
public void update(boolean enemyPresent);
}
public interface Subject {
public void register(Observer o);
public void unregister(Observer o);
public void notifyObserver();
}
Observable
public class VillianObserver implements Observer {
private boolean enemyPresent;
private static int heroIDTracker;
private int heroID;
private Subject villianObserver;
public VillianObserver(Subject villianObserver) {
this.villianObserver = villianObserver;
this.heroID = ++heroIDTracker;
System.out.println("New Observer " + this.heroID);
villianObserver.register(this);
}
#Override
public void update(boolean enemyPresent) {
this.enemyPresent = enemyPresent;
printResult();
}
public void printResult() {
System.out.println(heroID + " " + enemyPresent);
}
}
Enemy Status
import java.util.ArrayList;
public class EnemyStatus implements Subject {
private ArrayList<Observer> observers;
private boolean enemyPresent;
public EnemyStatus() {
// Creates an ArrayList to hold all observers
observers = new ArrayList<Observer>();
}
#Override
public void register(Observer newObserver) {
observers.add(newObserver);
}
#Override
public void unregister(Observer deleteObserver) {
// Get the index of the observer to delete
int heroIndex = observers.indexOf(deleteObserver);
// Print out message (Have to increment index to match
System.out.println("Observer " + (heroIndex+1) + " deleted");
// Removes observer from the ArrayList
observers.remove(heroIndex);
}
#Override
public void notifyObserver() {
for(Observer observer : observers) {
observer.update(enemyPresent);
}
}
public void setEnemyStatus(boolean enemyPresent) {
this.enemyPresent = enemyPresent;
notifyObserver();
}
}
JNotify is the Java library to observe file changes on the file system.
One piece of advice: Object(Input/Output)Streams are easy when you're just getting started but they lead you down a path of ruin. Objects get so easily BadVersion'ed. Object files are also relatively hard to inspect using a text editor. I'd advise you to try using a different data format (like JSON) instead.
Update: came up with new error about the provided java class
I have a tutorial for building an app for an external barcode scanner(use USB port) by using Java + provided Jar Library. I'm trying to build the same app by using the Xamarin.Forms and that Jar Library(through BindingsLibrary Project). However, I got an error
"Java.Lang.NoClassDefFoundError: " when I compiled my code. Does anybody have an idea about what I'm doing wrong?
This my java classes:
The USBScanFactory
package com.unistrong.qrcode;
import com.unistrong.pin.GOPOManager;
public class USBQRscanFactory {
private static USBQRscanFactory factory = new USBQRscanFactory();
static boolean mIsScanContinue = false;
private GOPOManager mGopoManager = GOPOManager.getInstance();
private OnScanListener mScanListener;
private QRScanManagerJNI qrScanManagerJNI;
private USBQRscanFactory() {
}
public static USBQRscanFactory createInstance() {
return factory;
}
public void init(OnScanListener onScanListener) {
this.mGopoManager.Pin11_High();
this.qrScanManagerJNI = new QRScanManagerJNI(onScanListener);
this.qrScanManagerJNI.callbackInit();
}
public void enableAddKeyValue(int i) {
QRScanManagerJNI.AddKeyValue(i);
}
public void open() {
this.mGopoManager.Pin11_Low();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
QRScanManagerJNI.OpenDev();
}
public void powerOn() {
this.mGopoManager.Pin11_High();
this.mGopoManager.openPower5V_3V3();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void powerOff() {
this.mGopoManager.Pin11_High();
this.mGopoManager.closePower5V_3V3();
}
public void scan_start() {
QRScanManagerJNI.QRScan();
}
On ScanListener:
package com.unistrong.qrcode;
public interface OnScanListener {
void scanReport(byte[] bArr);
void statusReport(int i);
}
And here is my code on Xamain:
public class OnScanListener : Java.Lang.Object, IOnScanListener
{
H myH = new H();
public void ScanReport(byte[] byteArray)
{
lock (myH)
{
if (null != byteArray && byteArray.Length > 0)
{
myH.SendMessage(myH.ObtainMessage(0, byteArray));
}
}
}
public void StatusReport(int i)
{
lock (myH)
{
myH.SendEmptyMessage(i);
}
}
}
#endregion
public MainPage()
{
usbScan = USBQRscanFactory.CreateInstance();
InitializeComponent();
}
int count = 0;
private void scanBtn_Clicked(object sender, EventArgs e)
{
count++;
//usbScan.Init(OnScanListener);
OnScanListener myOnScanListener = new OnScanListener();
usbScan.PowerOn();
usbScan.Init(myOnScanListener);
Barcode.Text = "";
openScanner(true);
usbScan.Scan_start();
}
//Open Scanner
private void openScanner(bool open)
{
if (open == mWorkingStateFlag) return;
if (open)
{
try
{
Java.Lang.Thread.Sleep(50);
usbScan.Open();
usbScan.EnableAddKeyValue(0);
}
catch (Java.Lang.InterruptedException e)
{
// TODO Auto-generated catch block
e.PrintStackTrace();
}
}
}
I have a server that contains an ArrayList in " ServerInfo " and when I try to take from ClientRMI an element of the ArrayList(in ServerInfo) for example adf.getSGM ( 0 ).incrementCount( ) ;
"count" does not increase it's as if every time I call it instantiates a new class SGM
in a few words I want to interact from ClientRMI with ArrayList that is on ServerInfo (SORRY FOR ENGLISH)
Hear are the classes :
SERVER
public class ServerRMI {
public static void main(String[] args) {
Registry registry = null;
String name = "ServerInfo";
try {
System.out.println("Init RMI");
ServerInfoInterface sir = ServerInfo.getInstance();
ServerInfoInterface stub = (ServerInfoInterface) UnicastRemoteObject.exportObject(sir, 0);
registry = LocateRegistry.createRegistry(9000);
registry.bind(name, stub);
System.out.println("RMI OK");
System.out.println("Init SGM...");
for(int i=0;i<3;i++){
ServerInfo.getInstance().addSGM(new SGM());
}
System.out.println("Init SGM OK");
} catch (Exception e) {
System.out.println("RMI Error"+e.toString());
registry = null;
}
}
}
public class ServerInfo implements ServerInfoInterface{
private ArrayList<SGM> sgmHandler = new ArrayList<SGM>();
// Singleton pattern
private static ServerInfo instance;
// Singleton pattern
public static ServerInfo getInstance() {
if (instance == null){
System.out.println("ServerInfo new instance");
instance = new ServerInfo();
}
return instance;
}
#Override
public synchronized void addSGM(SGM sgm) throws RemoteException {
sgmHandler.add(sgm);
}
#Override
public synchronized SGM getSGM(int i) throws RemoteException {
return sgmHandler.get(i);
}
}
public interface ServerInfoInterface extends Remote{
public void addSGM(SGM sgm) throws RemoteException;
public SGM getSGM(int i) throws RemoteException;
}
public class SGM implements Serializable{
/**
*
*/
private static final long serialVersionUID = -4756606091542270097L;
private int count=0;
public void incrementCount(){
count++;
}
public void decrementCount(){
count--;
}
public int getCount(){
return count;
}
}
CLIENT
public class ClientRMI {
private ServerInfoInterface sgmInterface;
public void startServer() {
String name = "ServerInfo";
Registry registry;
try {
registry = LocateRegistry.getRegistry(9000);
try {
sgmInterface = (ServerInfoInterface) registry.lookup(name);
sgmInterface.getSGM(0).incrementCount();
System.out.println(sgmInterface.getSGM(0).getCount()); // always 0
} catch (AccessException e) {
System.out.println("RIM AccessException"+ e.toString());
} catch (RemoteException e) {
System.out.println("RIM RemoteException"+ e.toString());
} catch (NotBoundException e) {
System.out.println("RIM NotBoundException"+ e.toString());
}
} catch (RemoteException e) {
System.out.println("RIM RemoteException registry"+ e.toString());
}
}
}
You're creating an SGM at the server, passing it via Serialization to the client, incrementing its count at the client, and then expecting that count to be magically increased at the server.
It can't work.
You will have to make SGM a remote object, with its own remote interface, or else provide a remote method in the original remote interface to increment the count of a GSM, specified by index.
Below are my service, serviceImpl and async callback interfaces. Appreciate if someone can help me understand why the submitTeam(...) isn't being called (I howeve see that isValidEmail(...) is being invoked when used). At least provide me the approach for debugging this as currently I am unable to use eclipse debugger (eclipse is not stopping at breakpoints) and the sysout/syserr statements are not being logged to the console either :-(.
#RemoteServiceRelativePath("registrationService")
public interface RegistrationService extends RemoteService
{
Boolean isValidEmail(String email);
String submitTeam(String teamName, List<Player> players);
}
public interface RegistrationServiceAsync
{
void isValidEmail(String email, AsyncCallback<Boolean> callback);
void submitTeam(String teamName, List<Player> players, AsyncCallback<String> callback);
}
public class SubmitTeamCallback implements AsyncCallback<String> {
private final Label status;
public SubmitTeamCallback(Label s) {
status = s;
}
public void onFailure(Throwable caught) {
status.setText(caught.getMessage());
}
public void onSuccess(String result) {
System.out.println("" + getClass().getName() + " : " + result);
status.setText(result);
}
}
public class RegistrationCallback implements AsyncCallback<Boolean>
{
private final Label status;
private final PlayerWidget playerWidget;
private Boolean isValidSharedFlag;
public RegistrationCallback(Label s, PlayerWidget pw, Boolean isValid)
{
status = s;
playerWidget = pw;
setIsValidSharedFlag(isValid);
}
public void onFailure(Throwable caught)
{
status.setText(caught.getMessage());
}
public void onSuccess(Boolean result)
{
if (result.equals(Boolean.FALSE))
{
playerWidget.invalidEmail();
String oldText = status.getText();
status.setText(oldText + "Please specify a valid email address for the captain.");
setIsValidSharedFlag(Boolean.FALSE);
} else
{
playerWidget.validEmail();
String newText = status.getText().replace("Please specify a valid email address for the captain.", "");
status.setText(newText);
setIsValidSharedFlag(Boolean.TRUE);
}
}
public void setIsValidSharedFlag(Boolean isValidSharedFlag)
{
this.isValidSharedFlag = isValidSharedFlag;
}
public Boolean getIsValidSharedFlag()
{
return isValidSharedFlag;
}
}
public class RegistrationServiceImpl extends RemoteServiceServlet implements
RegistrationService {
Logger logger = Logger.getLogger("");
private final Emailer emailer = new Emailer();
private final EmailValidator validator = new EmailValidator();
public Boolean isValidEmail(String email) {
return validator.validate(email);
}
public String submitTeam(String teamName, List<Player> players) {
logger.log(Level.SEVERE, "This is a test log");
System.out.println("This is a test log");
boolean emailSent = false;
for (Player p : players) {
System.out.println("Emailing to captain");
if (p instanceof Captain) {
if (!validator.validate(p.getEmail())) {
return "Please specify a valid email";
}
System.out.println("Emailing to captain");
emailSent = emailer.email(p);
}
}
if (emailSent) {
System.out.println("Email sent successfully");
return teamName
+ " has been successfully registered. Please pay the registration fee to confirm registration. Thank you.";
} else {
return "Unable to send email. Please email the team details [Team name, minimum of 6 players, captain's email address and phone number] to funpluscharity#gmail.com";
}
}
}
Below method is going to invoke the RPC calls
private void registerTeam() {
System.out.println("Received request to dubmit team");
StringBuilder statusText = new StringBuilder();
try {
Boolean isValid = true;
RegistrationServiceAsync service = (RegistrationServiceAsync) GWT
.create(RegistrationService.class);
ServiceDefTarget serviceDef = (ServiceDefTarget) service;
System.err.println(".........." + GWT.getModuleBaseURL());
serviceDef
.setServiceEntryPoint("/services/registrationService");
if (teamName.getText() == null
|| teamName.getText().length() == 0) {
isValid = false;
statusText.append("Please specify team name. ");
}
Player captain = getCaptain();
if (!atleast6PlayersAreSpecified()) {
isValid = false;
statusText.append("Please specify atleast 6 players. ");
}
if (captain == null) {
isValid = false;
statusText.append("Please designate a captain. ");
}
System.out.println("Is request valid? " + isValid);
if (isValid.equals(Boolean.TRUE)) {
System.out.println("RPC - submitTeam start ");
System.out.println("" + getPlayers());
SubmitTeamCallback callback = new SubmitTeamCallback(status);
service.submitTeam(teamName.getText(), getPlayers(),
callback);
System.out.println("RPC - submitTeam end");
} else {
status.setText(statusText.toString());
}
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
}
}
Made some progress after adding Window.alert(...) based on #Pistol suggestion and it is going to onFailure(Throwable t) method of the SubmitTeamCallback class.
unknown.com_google_gwt_user_client_rpc_SerializationException_SerializationException__Ljava_lang_String_2V(Unknown Source)
An alternative method to debug client side code is using Window.alert(...). For example placing it in your callback onFailure() method to see caught messages for a start. Or you can use FireBug or something similar to see if the rpc-call is actually being made?
Edit :
Are you sure your Player class implements IsSerializable and have an empty constructor? Check out Serializable User-Defined Classes.
Figured this out. The POJO's should have a default constructor and the one's I am using didn't have one. GWT compiler didn't complain either. Not sure why.