I am trying to call the webservice for my application. If I call it in a sample project it is working perfectly fine. But when I merge it with My Java FX it is giving me so many errors. Web Service Client is auto generated using the Eclipse. I am trying to call the Methods only. Can Anyone help me?
Error: **Correction** I have edited it and I am using now JAVASE-15 and JVAFX-SDK 11.0.2
The package javax.xml.namespace is accessible from more than one module: java.xml, jaxrpc
Correction Update 2: I have removed Java.xml dependencies and module-info file as well.
but the new error is this
**Error: Could not find or load main class gload.Main
Caused by: java.lang.NoClassDefFoundError: javafx/application/Application**
and IF I keep the module info file it shows:
**Error occurred during initialization of boot layer
java.lang.module.FindException: Module javafx.graphics not found, required by gload**
Model:
package gload.model;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.swing.JOptionPane;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.datacontract.schemas._2004._07.PE_PPER_MyPdmWebServiceClient_Data.CustomerItem;
import org.datacontract.schemas._2004._07.PE_PPER_MyPdmWebServiceClient_Data.Result;
import org.tempuri.IService;
import org.tempuri.ServiceLocator;
public class PdmData
{
public String scode;
public boolean state = false;
public static String CdfFile;
public static String pdflocation;
public static String Custom_Ci;
public static String Generic_Ci;
public static String Mp_ref;
public static String Interface;
public static String Comments;
public static String PersoAppli;
public static String Code;
public static String Revision;
public static String Customer_Name;
public static String Customer_reference;
public static String getCode() {
return Code;
}
public static void setCode(String code) {
Code = code;
}
public static String getRevision() {
return Revision;
}
public static void setRevision(String revision) {
Revision = revision;
}
public static String getCustomer_Name() {
return Customer_Name;
}
public static void setCustomer_Name(String customer_Name) {
Customer_Name = customer_Name;
}
public static String getCustomer_reference() {
return Customer_reference;
}
public static void setCustomer_reference(String customer_reference) {
Customer_reference = customer_reference;
}
public static String getPersoAppli() {
return PersoAppli;
}
public static void setPersoAppli(String persoAppli) {
PersoAppli = persoAppli;
}
public static String getGeneric_Ci() {
return Generic_Ci;
}
public static void setGeneric_Ci(String generic_Ci) {
Generic_Ci = generic_Ci;
}
public static String getCdfFile() {
return CdfFile;
}
public static void setCdfFile(String cdfFile) {
CdfFile = cdfFile;
}
public static String getPdflocation() {
return pdflocation;
}
public static void setPdflocation(String pdflocation) {
PdmData.pdflocation = pdflocation;
}
public String Cdffile(String reference) {
ServiceLocator locator = new ServiceLocator(); -------->Web Service Locator and call
try {
IService basicHttpBinding_IService = locator.getBasicHttpBinding_IService();
Result result = basicHttpBinding_IService.getFilebyDcode(reference);
//To download the files
String link = result.getLocation();
System.out.println(link);
File out = new File("C:\\TempDownload\\" + reference +".zip"); //Creating a zip file to store the contents of download file
new Thread(new Download(link,out)).start();
//To Unzip the file
Path source = Paths.get("C:\\TempDownload\\" + reference +".zip");
Path target = Paths.get("C:\\TempDownload\\Unzip");
try {
unzipFolder(source, target);
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
}
//Creating a File object for directory
File directoryPath = new File("C:\\TempDownload\\Unzip\\Pre Ppc" + reference + "A_Released");
//List of all files and directories
String[] contents = directoryPath.list();
System.out.println("List of files and directories in the specified directory:");
FilenameFilter pdffilter = new FilenameFilter() {
public boolean accept(File dir, String name) {
String lowercaseName = name.toLowerCase();
if (lowercaseName.endsWith(".pdf")) {
return true;
} else {
return false;
}
}
};
String[] contents1 = directoryPath.list(pdffilter);
for(String fileName : contents1) {
System.out.println(fileName);
setCdfFile(fileName);
setPdflocation(directoryPath.toString());
}
//To extract the Data From PDF
File file = new File(getPdflocation() + "\\" + getCdfFile());
//FileInputStream fis = new FileInputStream(file);
PDDocument document = PDDocument.load(file);
PDFTextStripper pdfReader = new PDFTextStripper();
String docText = pdfReader.getText(document);
System.out.println(docText);
document.close();
//To extract details from document
String CI_Ref = "CI Ref";
int pos ;
pos = docText.indexOf(CI_Ref);
setGeneric_Ci(docText.substring(pos+7 , pos+15));
System.out.println("Generic CI: " + getGeneric_Ci());
//To get Details of CI
CustomerItem customerItem = basicHttpBinding_IService.getCiDetails(getGeneric_Ci());
setPersoAppli(customerItem.getPersoAppli());
setCode(customerItem.getCode());
setRevision(customerItem.getRevision());
setCustomer_Name(customerItem.getCustomerName());
setCustomer_reference(customerItem.getCustomerReference());
}catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Unable to reach Service : " + e.getMessage());
}
return getPersoAppli();
}
Module info file
module gload {
requires javafx.controls;
requires javafx.fxml;
requires java.desktop;
requires java.rmi;
requires java.base;
requires axis;
requires jaxrpc;
requires org.apache.pdfbox;
opens gload;
opens gload.views.main;
opens gload.utils;
opens gload.model;
opens gload.controllers;
opens org.tempuri;
opens org.datacontract.schemas._2004._07.PE_PPER_MyPdmWebServiceClient_Data;
}
and IF I keep Jaxrpc in classpath instead of module path I get error like this Description
The type javax.xml.rpc.ServiceException cannot be resolved. It is indirectly referenced from required .class files
OK, this won't really be an answer, more pointers to related issues and potential approaches to come up with solutions. But I'll post it as an answer as it is likely better to do that than lots of comments.
Unfortunately, you have multiple errors and issues, so I'll try to deal with some of them seperately.
According to:
Java FX Modular Application, Module not found (Java 11, Intellij)
The error:
Error occurred during initialization of boot layer
java.lang.module.FindException:
Module X not found, required by Y
can occur when --module-path is wrong and the module can't be found. Probably, that is at least one of your issues. The linked answer is for Idea and I don't use Eclipse, so I don't know how to resolve the issue in Eclipse, but perhaps you could do some research to find out.
Regarding:
The package javax.xml.namespace is accessible from more than one module
there is some info on what is going on here:
Eclipse is confused by imports ("accessible from more than one module").
This fix appears tricky to me. Please review the linked questions and solutions. It looks like either you need to either
Forego Java 9+ modularity OR
Manage your dependencies to not include the violating transitive dependency OR
Change to a library that doesn't rely on the broken library (probably the preferred solution in this case).
The broken library causing this issue is likely the version of jaxrpc you are using. My guess is that some of the relevant XML libraries were only added to standard Java in Java 9, but the jaxrpc library you are using was developed prior to that. So, jaxrpc either includes the XML libraries in its classes or makes use of a transitive library that does the same. This causes a conflict because the XML libraries can only be included once in the project.
Further info on your issues is in this answer:
Eclipse can't find XML related classes after switching build path to JDK 10
The info is so ugly . . . you could read the answer, it may either help or discourage you.
Some things you could do to help resolve the situation
What should be done about this is kind of tricky and will depend on your skill level and how or if you can solve it. I'll offer up some advice on some things you could do, but there are other options. You know your application better than I so you may be able to come up with better solutions for your application.
I'd advise separating these things out, just as a way of troubleshooting, get a project which works with all of the JavaFX components and one which works with all of the SOAP components and make sure they build and do what you want. Then try to combine the two projects either by integrating them into one project or running them in separate VMs with communication between the two (e.g. via an added REST API, though that is a much more complicated solution, so think hard about that before attempting it).
Also, upgrade to the latest version of JavaFX. I don't think it will fix your issue, but it can't hurt and it is possible some refinements in recent JavaFX versions may have done some things which might help ease some of your issues (though not all of them, as some of your issues stem from jaxrpc usage in a modular project, which is unrelated to JavaFX).
Also, and probably more importantly, consider using a different SOAP client framework that interacts better with modular Java 9+ than the broken implementation that jaxrpc appears to have.
In terms of whether you should make your application modular or not (include a module-info or not), I don't really know the best approach for you. Certainly, whichever way you choose you will run into issues. But, the issues and how to resolve them will be different depending on the chosen solution path (as I guess you have already discovered during the course of your investigation for the question).
If necessary, isolate the issues down to single separate issues. If you need help in resolving each separate issue post new questions that feature minimal reproducible example code to replicate the issue. Mind if you do so, that the code is absolutely minimal and also complete so that it replicates and asks about only one issue, not a combination of more than one and that the questions are appropriate tagged - e.g. if the question is about jaxrpc and modularity it should include jaxrpc and modular tags and no JavaFX code or tags (and vice versa) and certainly on pdf code or dependencies anywhere if that isn't part of the problem.
Related
Please note I do not have any previous experience with Java. I am having issues with the following tutorial for Py4j: https://www.py4j.org/getting_started.html
I installed Py4j in an Anaconda environment. I am working in Ubuntu. I set my classpath to include the .jar file for Py4j. When I try to compile the sample code on the above web-page I received an error saying the Stack symbol didn't exist. I tried to add a line of code to import it, but that did not help either (see images).
Error and Directory Structure (image)
Source code:
Stack.java
package py4j.examples;
import java.util.LinkedList;
import java.util.List;
public class Stack {
private List<String> internalList = new LinkedList<String>();
public void push(String element) {
internalList.add(0, element);
}
public String pop() {
return internalList.remove(0);
}
public List<String> getInternalList() {
return internalList;
}
public void pushAll(List<String> elements) {
for (String element : elements) {
this.push(element);
}
}
}
StackEntryPoint.java
package py4j.examples;
import py4j.GatewayServer;
import py4j.examples.Stack; // <-- I added this line but it does not solve the issue
public class StackEntryPoint {
private Stack stack;
public StackEntryPoint() {
stack = new Stack();
stack.push("Initial Item");
}
public Stack getStack() {
return stack;
}
public static void main(String[] args) {
GatewayServer gatewayServer = new GatewayServer(new StackEntryPoint());
gatewayServer.start();
System.out.println("Gateway Server Started");
}
}
I haven't used Java before, so I'm confused about how to link classes during compilation. I've tried looking extensively at Java documentation/resources online and questions related, but can't seem to solve this problem. Could someone point out what I'm doing incorrectly?
Thank you.
You are compiling class StackEntryPoint, but you have not compiled the Stack class yet. Do so first, otherwise it cannot use it to compile StackEntryPoint.
Normally your IDE would solve this for you, but you've got a special setup going here (with the Python integration) so I'm not sure how you'd integrate it.
Ideally, you'll build your Java library as a separate JAR using conventional Java tooling (e.g. Maven and IntelliJ IDEA), but it's not a bad exercise to learn to do it bare-bones first.
In my java code I call another 3rd party java class.
I want to catch that latter System.exit() exit code
So I use security-manager as suggested in this post
The problem is that I cannot read files now, I get permissions error
as seen in that post.
How can I catch the exit code and still read files?
Published class MyClass {
class MySecurityManager extends SecurityManager {
#Override
public void checkExit(int status) {
throw new SecurityException();
}
}
public void foo() {
MySecurityManager secManager = new MySecurityManager();
System.setSecurityManager(secManager);
try {
ConfigValidator.main(new String[]{"-dirs", SdkServiceConfig.s.PROPERTIES_FILE_PATH});
new FileInputStream(new File("/Users/eladb/WorkspaceQa/sdk-service/src/main/resources/convert_conditions.sh"));
} catch (SecurityException e) {
//Do something if the external code used System.exit()
String a = "1";
}
catch (Exception e) {
logger.error("failed converting properties file to proto", e);
}
}
}
You have two separate problems: Your trusted code cannot read the file, while the untrusted third-party library can still call System#exit unhindered. The former can be easily circumvented by granting further privileges to the trusted code; the latter is a tad trickier to address.
A bit of background
Privilege assignment
Code (the ProtectionDomains encapsulated by a thread's AccessControlContext) generally gets assigned Permissions in two ways: Statically, by the ClassLoader, upon class definition, and/or dynamically, by the Policy in effect. Other, less frequently encountered alternatives, exist as well: DomainCombiners, for instance, can modify AccessControlContexts' domains (and therefore the effective permissions of their respective code that is subject to authorization) on the fly, and custom domain implementations may use their own logic for permission implication, possibly disregarding or altering the semantics of the policy. By default the permission set of a domain is the union of its static and dynamic permissions. As for how exactly classes are mapped to domains, it is, for the most part, up to the loader's implementation. By default, all classes, JAR'ed or otherwise, residing beneath the same class path entry, are grouped under the same domain. More restrictive class loaders may choose to e.g. allocate a domain per class, which could be used to prevent communication even between classes within the same package.
Privilege evaluation
Under the default SecurityManager, for a privileged operation (an invocation of any method having a SecurityManager#checkXXX within its body) to succeed, every domain (of every class of every method) of the effective AccessControlContext must have been assigned, as explained above, the permission being checked. Recall however that the context need not necessarily represent "the truth" (the actual call stack)—system code gets optimized away early on, while AccessController#doPrivileged calls, along with the DomainCombiner potentially coupled to the AccessControlContext can modify the context's domains, and the authorization algorithm in its entirety, consequently.
Problem and workarounds
The issue with System#exit is that the corresponding permission (RuntimePermission("exitVM.*")) is one amongst few that are statically assigned by the default application class loader (sun.misc.Launcher$AppClassLoader) to all domains associated with classes loaded from the class path.
A number of alternatives come to mind:
Installing a custom SecurityManager which denies the particular right based on, e.g., the class attempting to terminate the JVM process.
Loading the third-party library from a "remote" location (a directory outside of the class path), so that it gets treated as "untrusted" code by its class loader.
Authoring and installing a different application class loader, which does not assign the extraneous permission.
Plugging a custom domain combiner into the access control context, which replaces, at the time of an authorization decision, all third-party domains with equivalent ones that do not have the offending permission.
I should, for the sake of completeness, note that at the Policy level, unfortunately, nothing can be done to negate statically assigned permissions.
The first option is overall the most convenient one, but I will not explore it further because:
The default SecurityManager is quite flexible, thanks to the handful of components (AccessController et al.) it interacts with. The background section in the beginning aimed to serve as a reminder of that flexibility, which "quick-n'-dirty" method overrides tend to cripple.
Careless modifications of the default implementation might cause (system) code to misbehave in curious ways.
Frankly, because it's boring―it's the one-size-fits-all solution perpetually advocated, while the fact that the default manager was standardized in 1.2 for a reason has long been forgotten.
The second alternative is easy to implement but impractical, complicating either development or the build process. Assuming you are not planning to invoke the library solely reflectively, or aided by interfaces present on the class path, it would have to be present initially, during development, and relocated before execution.
The third is, at least in the context of a standalone Java SE application, fairly straightforward and should not pose too much of a burden on performance. It is the approach I will favour herein.
The last option is the most novel and least convenient. It is hard to securely implement, has the greatest potential for performance degradation, and burdens client code with ensuring presence of the combiner prior to every delegation to untrusted code.
Proposed solution
The custom ClassLoader
The following is to be used as the replacement of the default application loader, or alternatively as the context class loader, or the loader used to load at least the untrusted classes. There is nothing novel to this implementation—all it does is prevent delegation to the default application class loader when the class in question is assumed to not be a system one. URLClassLoader#findClass, in turn, does not assign RuntimePermission("exitVM.*") to the domains of the classes it defines.
package com.example.trusted;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.regex.Pattern;
public class ClasspathClassLoader extends URLClassLoader {
private static final Pattern SYSTEM_CLASS_PREFIX = Pattern.compile("((java(x)?|sun|oracle)\\.).*");
public ClasspathClassLoader(ClassLoader parent) {
super(new URL[0], parent);
String[] classpath = System.getProperty("java.class.path").split(File.pathSeparator);
for (String classpathEntry : classpath) {
try {
if (!classpathEntry.endsWith(".jar") && !classpathEntry.endsWith("/")) {
// URLClassLoader assumes paths without a trailing '/' to be JARs by default
classpathEntry += "/";
}
addURL(new URL("file:" + classpathEntry));
}
catch (MalformedURLException mue) {
System.err.println(MessageFormat.format("Erroneous class path entry [{0}] skipped.", classpathEntry));
}
}
}
#Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> ret;
synchronized (getClassLoadingLock(name)) {
ret = findLoadedClass(name);
if (ret != null) {
return ret;
}
if (SYSTEM_CLASS_PREFIX.matcher(name).matches()) {
return super.loadClass(name, resolve);
}
ret = findClass(name);
if (resolve) {
resolveClass(ret);
}
}
return ret;
}
}
If you also wish to fine-tune the domains assigned to loaded classes, you will additionally have to override findClass. The following variant of the loader is a very crude attempt at doing so. constructClassDomain therein merely creates one domain per class path entry (which is more or less the default), but can be modified to do something different.
package com.example.trusted;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public final class ClasspathClassLoader extends URLClassLoader {
private static final Pattern SYSTEM_CLASS_PREFIX = Pattern.compile("((java(x)?|sun|oracle)\\.).*");
private static final List<WeakReference<ProtectionDomain>> DOMAIN_CACHE = new ArrayList<>();
// constructor, loadClass same as above
#Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
URL classOrigin = getClassResource(name);
if (classOrigin == null) {
return super.findClass(name);
}
URL classCodeSourceOrigin = getClassCodeSourceResource(classOrigin);
if (classCodeSourceOrigin == null) {
return super.findClass(name);
}
return defineClass(name, readClassData(classOrigin), constructClassDomain(classCodeSourceOrigin));
}
private URL getClassResource(String name) {
return AccessController.doPrivileged((PrivilegedAction<URL>) () -> getResource(name.replace(".", "/") + ".class"));
}
private URL getClassCodeSourceResource(URL classResource) {
for (URL classpathEntry : getURLs()) {
if (classResource.getPath().startsWith(classpathEntry.getPath())) {
return classpathEntry;
}
}
return null;
}
private ByteBuffer readClassData(URL classResource) {
try {
BufferedInputStream in = new BufferedInputStream(classResource.openStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
int i;
while ((i = in.read()) != -1) {
out.write(i);
}
return ByteBuffer.wrap(out.toByteArray());
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
private ProtectionDomain constructClassDomain(URL classCodeSourceResource) {
ProtectionDomain ret = getCachedDomain(classCodeSourceResource);
if (ret == null) {
CodeSource cs = new CodeSource(classCodeSourceResource, (Certificate[]) null);
DOMAIN_CACHE.add(new WeakReference<>(ret = new ProtectionDomain(cs, getPermissions(cs), this, null)));
}
return ret;
}
private ProtectionDomain getCachedDomain(URL classCodeSourceResource) {
for (WeakReference<ProtectionDomain> domainRef : DOMAIN_CACHE) {
ProtectionDomain domain = domainRef.get();
if (domain == null) {
DOMAIN_CACHE.remove(domainRef);
}
else if (domain.getCodeSource().implies(new CodeSource(classCodeSourceResource, (Certificate[]) null))) {
return domain;
}
}
return null;
}
}
The "unsafe" code
package com.example.untrusted;
public class Test {
public static void testExitVm() {
System.out.println("May I...?!");
System.exit(-1);
}
}
The entry point
package com.example.trusted;
import java.security.AccessControlException;
import java.security.Permission;
import com.example.untrusted.Test;
public class Main {
private static final Permission EXIT_VM_PERM = new RuntimePermission("exitVM.*");
public static void main(String... args) {
System.setSecurityManager(new SecurityManager());
try {
Test.testExitVm();
}
catch (AccessControlException ace) {
Permission deniedPerm = ace.getPermission();
if (EXIT_VM_PERM.implies(deniedPerm)) {
ace.printStackTrace();
handleUnauthorizedVmExitAttempt(Integer.parseInt(deniedPerm.getName().replace("exitVM.", "")));
}
}
}
private static void handleUnauthorizedVmExitAttempt(int exitCode) {
System.out.println("here let me do it for you");
System.exit(exitCode);
}
}
Testing
Packaging
Place the loader and the main class in one JAR (let's call it trusted.jar) and the demo untrusted class in another (untrusted.jar).
Assigning privileges
The default Policy (sun.security.provider.PolicyFile) is backed by the file at <JRE>/lib/security/java.policy, as well as any of the files referenced by the policy.url.n properties in <JRE>/lib/security/java.security. Modify the former (the latter should hopefully be empty by default) as follows:
// Standard extensions get all permissions by default
grant codeBase "file:${{java.ext.dirs}}/*" {
permission java.security.AllPermission;
};
// no default permissions
grant {};
// trusted code
grant codeBase "file:///path/to/trusted.jar" {
permission java.security.AllPermission;
};
// third-party code
grant codeBase "file:///path/to/untrusted.jar" {
permission java.lang.RuntimePermission "exitVM.-1", "";
};
Note that it is virtually impossible to get components extending the security infrastructure (custom class loaders, policy providers, etc.) to work properly without granting them AllPermission.
Running
Run:
java -classpath "/path/to/trusted.jar:/path/to/untrusted.jar" -Djava.system.class.loader=com.example.trusted.ClasspathClassLoader com.example.trusted.Main
The privileged operation should succeed.
Next comment out the RuntimePermission under untrusted.jar, within the policy file, and re-run. The privileged operation should fail.
As a closing note, when debugging AccessControlExceptions, running with -Djava.security.debug=access=domain,access=failure,policy can help track down offending domains and policy configuration issues.
SQLUtils.java:
import org.openide.util.Lookup;
import java.util.ServiceLoader; // This doesn't work either
public class SQLUtils {
public static DBDriver getDriver(String prefix) {
for(DBDriver e : Lookup.getDefault().lookupAll(DBDriver.class)) {
System.out.println(e.getPrefix());
if(e.getPrefix().equalsIgnoreCase(prefix)) {
return e;
}
}
return null;
}
}
MySQLDriver.java:
public class MySQLDriver implements DBDriver {
#Override
public String getPrefix() {
return "mysql";
}
}
DBDriver.java:
import java.io.Serializable;
public interface DBDriver extends Serializable {
public String getPrefix();
}
Main.java:
public class Main {
public static void main(String[] args) {
DBDriver d = SQLUtils.getDriver("mysql");
}
}
This does nothing when running it, it cannot find any classes implementing.
What the program is trying to do is get the driver that is entered as a parameter for SQLUtils.getDriver(String prefix) (in Main.java).
For some reason I cannot get this to work.
I'm not familiar with OpenIDE Lookup mechanism, but I am familiar with the Java ServiceLoader mechanism.
You need to provide a file in the META-INF/services/ folder describing what classes implement specific interfaces. From the Java Docs describing the ServiceLoader class is this example:
If com.example.impl.StandardCodecs is an implementation of the
com.example.CodecSet service then its jar file also contains a file
named
META-INF/services/com.example.CodecSet
This file contains the single line:
com.example.impl.StandardCodecs # Standard codecs implementing com.example.CodecSet
What you are missing is a similar file that needs to be included on your classpath or within your JAR file.
You don't include you package names so I cannot provide a more direct example to help solve your problem.
I dropped the NetBeans API and switched to Reflections. I implemented Maven and ran it with IntelliJ. Works well for me.
Somewhat of a followup to How to use public class frome .java file in other processing tabs?; using the example from Usage class from .java file - is there a full doc for that? - Processing 2.x and 3.x Forum, I have this:
/tmp/Sketch/Sketch.pde
// forum.processing.org/two/discussion/3677/
// usage-class-from-java-file-is-there-a-full-doc-for-that
Foo tester;
void setup() {
size(600, 400, JAVA2D);
smooth(4);
noLoop();
clear();
rectMode(Foo.MODE);
fill(#0080FF);
stroke(#FF0000);
strokeWeight(3);
tester = new Foo(this);
tester.drawBox();
}
/tmp/Sketch/Foo.java
import java.io.Serializable;
//import peasy.org.apache.commons.math.geometry.Rotation;
//import peasy.org.apache.commons.math.geometry.Vector3D;
import processing.core.PApplet;
import processing.core.PGraphics;
public class Foo implements Serializable {
static final int GAP = 15;
static final int MODE = PApplet.CORNER;
final PApplet p;
Foo(PApplet pa) {
p = pa;
}
void drawBox() {
p.rect(GAP, GAP, p.width - GAP*2, p.height - GAP*2);
}
}
The example runs fine as is - but if I uncomment the import peasy.org... lines, then compilation fails with:
The package "peasy" does not exist. You might be missing a library.
Libraries must be installed in a folder named 'libraries' inside the 'sketchbook' folder.
Of course, I do have PeasyCam installed, under /path/to/processing-2.1.1/modes/java/libraries/peasycam/ - and it works fine, if I do a import peasy.*; from a .pde sketch.
I guess, this has something to do with paths - apparently pure Java files in a sketch, do not refer to the same library paths as .pde files in a sketch.
Is it possible to get this sketch to compile with the import peasy.org... lines (other than, I guess, copying/symlinking the peasycam library in the sketch folder, here /tmp/Sketch/ <--- EDIT: just tried symlinking as described, it doesn't work; the same error is reported)?
This is where you learn that Processing isn't actually Java, it just has a similar(ish) syntax and can run its code in the JVM by aggregating all .pde files into a single class that can be compiled for running on the JVM. Processing has its own rules for dealing with imports and the like.
Why not just do this entirely in Processing instead?
class Foo {
static int MODE = ...;
static int GAP = ...;
PApplet sketch;
public Foo(PApplet _sketch) {
sketch = _sketch;
...
}
void drawBox() {
sketch.rect(GAP, GAP, p.width - GAP*2, p.height - GAP*2);
}
...
}
and then make sure to have that in a file Foo.pde or something in the same dir as your sketch, with your sketch loading in the peasy library through the regular Processing import mechanism?
Ok, thanks to #MikePomaxKamermans answer, especially "by aggregating all .pde files into a single class", I simply tried importing peasy in the .pde file before the first reference to foo; that is, in /tmp/Sketch/Sketch.pde I now have:
// forum.processing.org/two/discussion/3677/
// usage-class-from-java-file-is-there-a-full-doc-for-that
import peasy.*; // add this
Foo tester;
...
... and then the sketch compiles without a problem (but note: while this approach works for this example, it somehow didn't work in the original problem that drove me to post the question).
I've run through the Google Web Toolkit StockWatcher Tutorial using Eclipse and the Google Plugin, and I'm attempting to make some basic changes to it so I can better understand the RPC framework.
I've modified the "getStocks" method on the StockServiceImpl server-side class so that it returns an array of Stock objects instead of String objects. The application compiles perfectly, but the Google Web Toolkit is returning the following error:
"No source code is available for type com.google.gwt.sample.stockwatcher.server.Stock; did you forget to inherit a required module?"
It seems that the client-side classes can't find an implementation of the Stock object, even though the class has been imported. For reference, here is a screenshot of my package hierarchy:
I suspect that I'm missing something in web.xml, but I have no idea what it is. Can anyone point me in the right direction?
EDIT: Forgot to mention that the Stock class is persistable, so it needs to stay on the server-side.
After much trial and error, I managed to find a way to do this. It might not be the best way, but it works. Hopefully this post can save someone else a lot of time and effort.
These instructions assume that you have completed both the basic StockWatcher tutorial and the Google App Engine StockWatcher modifications.
Create a Client-Side Implementation of the Stock Class
There are a couple of things to keep in mind about GWT:
Server-side classes can import client-side classes, but not vice-versa (usually).
The client-side can't import any Google App Engine libraries (i.e. com.google.appengine.api.users.User)
Due to both items above, the client can never implement the Stock class that we created in com.google.gwt.sample.stockwatcher.server. Instead, we'll create a new client-side Stock class called StockClient.
StockClient.java:
package com.google.gwt.sample.stockwatcher.client;
import java.io.Serializable;
import java.util.Date;
public class StockClient implements Serializable {
private Long id;
private String symbol;
private Date createDate;
public StockClient() {
this.createDate = new Date();
}
public StockClient(String symbol) {
this.symbol = symbol;
this.createDate = new Date();
}
public StockClient(Long id, String symbol, Date createDate) {
this();
this.id = id;
this.symbol = symbol;
this.createDate = createDate;
}
public Long getId() {
return this.id;
}
public String getSymbol() {
return this.symbol;
}
public Date getCreateDate() {
return this.createDate;
}
public void setId(Long id) {
this.id = id;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
}
Modify Client Classes to Use StockClient[] instead of String[]
Now we make some simple modifications to the client classes so that they know that the RPC call returns StockClient[] instead of String[].
StockService.java:
package com.google.gwt.sample.stockwatcher.client;
import com.google.gwt.sample.stockwatcher.client.NotLoggedInException;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
#RemoteServiceRelativePath("stock")
public interface StockService extends RemoteService {
public Long addStock(String symbol) throws NotLoggedInException;
public void removeStock(String symbol) throws NotLoggedInException;
public StockClient[] getStocks() throws NotLoggedInException;
}
StockServiceAsync.java:
package com.google.gwt.sample.stockwatcher.client;
import com.google.gwt.sample.stockwatcher.client.StockClient;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface StockServiceAsync {
public void addStock(String symbol, AsyncCallback<Long> async);
public void removeStock(String symbol, AsyncCallback<Void> async);
public void getStocks(AsyncCallback<StockClient[]> async);
}
StockWatcher.java:
Add one import:
import com.google.gwt.sample.stockwatcher.client.StockClient;
All other code stays the same, except addStock, loadStocks, and displayStocks:
private void loadStocks() {
stockService = GWT.create(StockService.class);
stockService.getStocks(new AsyncCallback<String[]>() {
public void onFailure(Throwable error) {
handleError(error);
}
public void onSuccess(String[] symbols) {
displayStocks(symbols);
}
});
}
private void displayStocks(String[] symbols) {
for (String symbol : symbols) {
displayStock(symbol);
}
}
private void addStock() {
final String symbol = newSymbolTextBox.getText().toUpperCase().trim();
newSymbolTextBox.setFocus(true);
// Stock code must be between 1 and 10 chars that are numbers, letters,
// or dots.
if (!symbol.matches("^[0-9a-zA-Z\\.]{1,10}$")) {
Window.alert("'" + symbol + "' is not a valid symbol.");
newSymbolTextBox.selectAll();
return;
}
newSymbolTextBox.setText("");
// Don't add the stock if it's already in the table.
if (stocks.contains(symbol))
return;
addStock(new StockClient(symbol));
}
private void addStock(final StockClient stock) {
stockService.addStock(stock.getSymbol(), new AsyncCallback<Long>() {
public void onFailure(Throwable error) {
handleError(error);
}
public void onSuccess(Long id) {
stock.setId(id);
displayStock(stock.getSymbol());
}
});
}
Modify the StockServiceImpl Class to Return StockClient[]
Finally, we modify the getStocks method of the StockServiceImpl class so that it translates the server-side Stock classes into client-side StockClient classes before returning the array.
StockServiceImpl.java
import com.google.gwt.sample.stockwatcher.client.StockClient;
We need to change the addStock method slightly so that the generated ID is returned:
public Long addStock(String symbol) throws NotLoggedInException {
Stock stock = new Stock(getUser(), symbol);
checkLoggedIn();
PersistenceManager pm = getPersistenceManager();
try {
pm.makePersistent(stock);
} finally {
pm.close();
}
return stock.getId();
}
All other methods stay the same, except getStocks:
public StockClient[] getStocks() throws NotLoggedInException {
checkLoggedIn();
PersistenceManager pm = getPersistenceManager();
List<StockClient> stockclients = new ArrayList<StockClient>();
try {
Query q = pm.newQuery(Stock.class, "user == u");
q.declareParameters("com.google.appengine.api.users.User u");
q.setOrdering("createDate");
List<Stock> stocks = (List<Stock>) q.execute(getUser());
for (Stock stock : stocks)
{
stockclients.add(new StockClient(stock.getId(), stock.getSymbol(), stock.getCreateDate()));
}
} finally {
pm.close();
}
return (StockClient[]) stockclients.toArray(new StockClient[0]);
}
Summary
The code above works perfectly for me when deployed to Google App Engine, but triggers an error in Google Web Toolkit Hosted Mode:
SEVERE: [1244408678890000] javax.servlet.ServletContext log: Exception while dispatching incoming RPC call
com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract com.google.gwt.sample.stockwatcher.client.StockClient[] com.google.gwt.sample.stockwatcher.client.StockService.getStocks() throws com.google.gwt.sample.stockwatcher.client.NotLoggedInException' threw an unexpected exception: java.lang.NullPointerException: Name is null
Let me know if you encounter the same problem or not. The fact that it works in Google App Engine seems to indicate a bug in Hosted Mode.
GWT needs the .java file in addition to the .class file. Additionally, Stock needs to be in the "client" location of a GWT module.
The GWT compiler doesn't know about Stock, because it's not in a location it looks in. You can either move it to the client folder, or if it makes more sense leave it where it is and create a ModuleName.gwt.xml that references any other classes you want, and get your Main.gwt.xml file to inherit from that.
eg: DomainGwt.gwt.xml
<module>
<inherits name='com.google.gwt.user.User'/>
<source path="javapackagesabovethispackagegohere"/>
</module>
and:
<module rename-to="gwt_ui">
<inherits name="com.google.gwt.user.User"/>
<inherits name="au.com.groundhog.groundpics.DomainGwt"/>
<entry-point class="au.com.groundhog.groundpics.gwt.client.GPicsUIEntryPoint"/>
</module>
There's a better answer here: GWT Simple RPC use case problem : Code included
Basically, you can add parameters to your APPNAME.gwt.xml file so the compiler to give the compiler a path to the server-side class.
I was getting the same issue and the "mvn gwt:compile" output was not very helpful.
Instead, when I tried deploying to tomcat (via the maven tomcat plugin: mvn tomcat:deploy) I got helpful error messages.
A few things I had to fix up:
Make the object that is sent from the client to the server implement Serializable
Add an empty-arg constructor to that same object
Yes, it is sure that we need to use the Serialization for getting the server objects to the client. These modile?? file settings won't work to use the Stock class in the client side.
In your case you have only one class Stock and you can create a StockClient in client side. It is easy. But what will be the solution if anyone having more classes. Something like the properties of this class are also some other type of classes.
Example: stock.getEOD(date).getHigh();
getEOD will return another class with the given date and that class has the getHigh method.
What to do in such big cases? I don't think creating all classes implementing serialization in client side is good for that. Then we have to write code in both server and client. all classes two times.
Keying off of rustyshelf's answer above ...
In my case I needed to edit the ModuleName.gwt.xml file and add the following:
<source path='client'/>
<source path='shared'/>
I created my project with the New->Web Application Project wizard but unchecked the Generate project sample code option. I then created the shared package. Had I not unchecked that, the package would have been created for me and the xml file modified per the above.
There is a far more simple and easy solution for that. If you want to send an object of your custom designed class from server side to client side you should define this custom class in shared package.
For example for your case the you just have to carry the Stock.java class (by drag and drop) into
com.google.gwt.sample.stockwatcher.shared
package. However from your package hierarchy screenshot it seems that you had deleted this shared package. Just re-create this package and drop the Stock.java inside it and let the game begin.