I am trying to understand GWT generators but facing few issues. I am trying to display the compile time in an app using generators and running into this error -
Rebind result 'com.example.client.Function' must be a class
Here is what i have -
This is how i am calling my generated method -
Function b = GWT.create(Function.class);
label.setText(b.getBuildTime());
gwt.xml-
<generate-with class="example.frontend.client.gin.FunctionGenerator">
<when-type-assignable class="com.example.frontend.client.gin.Function" />
</generate-with>
Function.java
package com.example.frontend.client.gin;
public interface Function{
public String getBuildTime();
}
Generator class -
package com.example.frontend.egenerator;
import java.io.PrintWriter;
import java.util.Date;
import com.google.gwt.core.ext.Generator;
import com.google.gwt.core.ext.GeneratorContext;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.example.frontend.client.gin.Function;
public class FunctionGenerator extends Generator {
private static final String IMPL_TYPE_NAME = Function.class.getSimpleName() + "Impl";
private static final String IMPL_PACKAGE_NAME = Function.class.getPackage().getName();
#Override
public String generate(final TreeLogger logger, final GeneratorContext context, final String requestedClass) throws UnableToCompleteException {
TypeOracle typeOracle = context.getTypeOracle();
JClassType functionType = typeOracle.findType(requestedClass);
assert Function.class.equals(functionType.getClass());
ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(IMPL_PACKAGE_NAME, IMPL_TYPE_NAME);
composerFactory.addImport(Function.class.getCanonicalName());
composerFactory.addImplementedInterface(Function.class.getName());
PrintWriter printWriter = context.tryCreate(logger, IMPL_PACKAGE_NAME, IMPL_TYPE_NAME);
SourceWriter sourceWriter = composerFactory.createSourceWriter(context, printWriter);
if(sourceWriter != null) {
sourceWriter.print("public String getBuildTime() {");
sourceWriter.print(" return \"" + new Date() + "\" ;");
sourceWriter.print("}");
sourceWriter.commit(logger);
}
return IMPL_PACKAGE_NAME + "." + IMPL_TYPE_NAME;
}
}
Any ideas, what I am missing?
I believe you also need to null check the PrintWriter created by tryCreate, as it may return null. On the other hand, createSourceWriter will not return null, so no need to null check that.
Your generate-with is also incorrect, at least for the sample that you have here. It should have a different package (according to your FunctionGenerator source at least), com.example.frontend.egenerator, not com.example.frontend.client.gin:
<generate-with class="com.example.frontend.egenerator.FunctionGenerator">
<when-type-assignable class="com.example.frontend.client.gin.Function" />
</generate-with>
In general, your generators should not be in the client package, if for no other reason than preventing spurious errors which slow down the compiler (and really slow down super dev mode).
Beyond that, the full log could help a lot to track down the issue, though without mapping the generator correctly there wouldn't be much of an error. Also be sure to compile with strict turned on when working on generators to ensure that the compiler fails as soon as possible and you can stop at the very first error.
With all of that said, tend to avoid new Generators at this point - they will slow down Super Dev Mode slightly (since they must be re-run every time you refresh), and they will not be supported in future versions of GWT. Annotation Processors (aka APT) are the preferred way to do this, but in your case you might also just be able to generate the class in ant or maven with a plugin.
Related
I am trying to delete a DLL which has been loaded into JNA and later disposed. I have tried all the solutions described in the answer to this question, but they are not working: How to dispose library loaded with JNA
Here is code I've tried without a time delay:
import java.io.File;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
class Filter {
private static ExtDLLTool DLLUtil;
final private static String dllPath = "./ExternalDownloader_64.dll";
static {
DLLUtil = (ExtDLLTool) Native.loadLibrary(dllPath, ExtDLLTool.class);
}
public static void main(String[] args) {
if (DLLUtil != null) {
DLLUtil = null;
NativeLibrary lib = NativeLibrary.getInstance(dllPath);
lib.dispose();
}
File dllFile = new File(dllPath);
if(dllFile.exists()){
boolean isDeleted = dllFile.delete();
if(!isDeleted){
System.out.println("Unable to delete dll file, since it hold by jvm");
}
}
}
private interface ExtDLLTool extends Library {
String validateNomination(String dloadProps);
}
}
I added a time delay to give the native code time to release the handle:
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
class Filter {
private static ExtDLLTool DLLUtil;
final private static String dllPath = "./ExternalDownloader_64.dll";
static {
DLLUtil = (ExtDLLTool) Native.loadLibrary(dllPath, ExtDLLTool.class);
}
public static void main(String[] args) throws Exception{
if (DLLUtil != null) {
DLLUtil = null;
NativeLibrary lib = NativeLibrary.getInstance(dllPath);
lib.dispose();
Thread.sleep(3000);
}
File dllFile = new File(dllPath);
if(dllFile.exists()){
Files.delete(Paths.get(dllPath));
// boolean isDeleted = dllFile.delete();
if(dllFile.exists()){
System.out.println("Unable to delete dll file, since it hold by jvm");
}
}
}
private interface ExtDLLTool extends Library {
String validateNomination(String dloadProps);
}
}
This code results in an exception implying the JVM has not released the file.
Exception in thread "main" java.nio.file.AccessDeniedException: .\ExternalDownloader_64.dll at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:83) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102) at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
In the end the problem is, that Native#open is called twice and Native#close only once. The assumption behind the presented code is, that:
NativeLibrary lib = NativeLibrary.getInstance(dllPath);
yields the same NativeLibrary instance, that is used by:
DLLUtil = (ExtDLLTool) Native.loadLibrary(dllPath, ExtDLLTool.class);
This assumption does not hold. Indeed NativeLibrary#load does use caching and if invoked with the same parameters it will yield only a single instance.
The codepath behind Native.loadLibrary passes two options to Native#loadLibrary: calling-convention and classloader. The calling-convention is equal to the default calling convention, so can be ignored. It is/would be automatically added in NativeLibrary#getInstance. The classloader though is not set to a default value and there is the difference. The options are part of the caching key and thus a second instance of the NativeLibrary is created and not the first returned.
To make it work, the call to NativeLibrary#getInstance must pass the correct classloader. If you modify the sample like this:
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
class Filter {
private static ExtDLLTool DLLUtil;
final private static String dllPath = "./ExternalDownloader_64.dll";
static {
DLLUtil = (ExtDLLTool) Native.loadLibrary(dllPath, ExtDLLTool.class);
}
public static void main(String[] args) throws Exception{
if (DLLUtil != null) {
DLLUtil = null;
NativeLibrary lib = NativeLibrary.getInstance(dllPath, ExtDLLTool.class.getClassLoader());
lib.dispose();
Thread.sleep(3000);
}
File dllFile = new File(dllPath);
if(dllFile.exists()){
Files.delete(Paths.get(dllPath));
// boolean isDeleted = dllFile.delete();
if(dllFile.exists()){
System.out.println("Unable to delete dll file, since it hold by jvm");
}
}
}
private interface ExtDLLTool extends Library {
String validateNomination(String dloadProps);
}
}
it works as expected.
After discussion there is another requirement: The cache path is only hit in a limited number of cases:
the library name is the filename of the library (without a prefix)
the library name is the absolute path to the library
the library name is the "base" name without any prefixes or suffixes the default library search mechanism adds (on windows ".dll" should be stripped, on linux "lib" prefix and ".so" suffix should be stripped) (UNTESTED!)
The TL;DR version: find the absolute path name and use that for interface loading and NativeLibrary loading.
I was able to reproduce the problem with your code, but only on Windows. When reproducible, I was able to successfully delete the file by adding a garbage collection suggestion before the time delay:
if (DLLUtil != null) {
DLLUtil = null;
NativeLibrary lib = NativeLibrary.getInstance(dllPath);
lib.close();
System.gc();
System.gc();
Thread.sleep(3000);
}
When JNA loads a Windows DLL via Native.loadLibrary(), it internally executes the WinAPI LoadLibraryExW function.
Internally the Java instance is stored in a map to be re-used when possible -- however for this to happen, it requires two things to look up the same Java object:
the DLL Path must be an absolute path
the options must match. In this case, you would need to pass the classloader as an argument as Matthias Bläsing indicated in his answer:
// if loaded like this:
DLLUtil = (ExtDLLTool) Native.loadLibrary(dllPath, ExtDLLTool.class);
// fetch from cache like this:
NativeLibrary lib = NativeLibrary.getInstance(dllPath, ExtDLLTool.class.getClassLoader());
lib.dispose();
This should allow you to delete the file.
However, in your case, with the relative path, the library is getting unloaded but the old java object isn't getting closed until GC occurs.
The dispose() (or close() as of 5.12) call in JNA eventually calls the Native.close() method which uses the Windows API FreeLibrary function. This unloads the DLL from the Process memory, so the advice on the linked question on how to dispose is still accurate in the case that you want to re-load the library. If you're not reloading the library, using dispose() (5.11-) or close() (5.12+) is optional.
If you must use a relative path, consider this approach using a PhantomReference inspired by this answer to track the deletion:
if (DLLUtil != null) {
// Unload the DLL from process memory
// Optional here, as it will be called by a cleaner on GC below
NativeLibrary lib = NativeLibrary.getInstance(dllPath);
lib.close();
System.out.println("Closed.");
// Remove any internal JVM references to the file
final ReferenceQueue rq = new ReferenceQueue();
final PhantomReference phantom = new PhantomReference(DLLUtil, rq);
DLLUtil = null;
// Poll until GC removes the reference
int count = 0;
while (rq.poll() == null) {
System.out.println("Waiting...");
Thread.sleep(1000);
if (++count > 4) {
// After 5 seconds prompt for GC!
System.out.println("Suggesting GC...");
System.gc();
}
}
System.out.println("Collected.");
}
The DLL was successfully deleted following this sequence. It did take a second GC call to take effect:
Closed.
Waiting...
Waiting...
Waiting...
Waiting...
Waiting...
Suggesting GC...
Waiting...
Suggesting GC...
Collected.
Deleted!
I have this code:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Date;
public class EmployeeProcessor {
public static void main(String[] args) {
Employee employee = new Employee();
employee.lastName = "Smith";
employee.firstName = "Adam";
employee.id = 123456789;
employee.salary = 50000;
try(FileOutputStream fileOutStr = new FileOutputStream("Employee.ser");
ObjectOutputStream objectOutStr = new ObjectOutputStream(fileOutStr)) {
objectOutStr.writeObject(employee);
System.out.println("An employee is externalized into the file Employee.ser");
} catch (IOException ioError){
ioError.printStackTrace();
}
}
}
But in Intellij IDEA ObjectOutputStream class is strikethrough Like this:
screenshot. When pointing mouse pointer over - this message appears: 'java.io.ObjectOutputStream' is deprecated. What does it mean?
When I run this code, IntelliJ opens "Edit Configurations" windows asking me to introduce VM options. But I leave it blank and run anyway.
IntelliJ IDEA has an intention action to annotate library classes as Deprecated using the External Annotations support. You've probably triggered this intention action by accident.
For the classes deprecated this way there supposed to be the reverse action: Deannotate, but it may not work (bug reported).
To fix it manually, find the annotations.xml file in a directory that is configured in the SDK Annotations tab and edit/remove it.
UPDATE: Deannoate action should work now, but only while inside the annotated class itself, not from its reference.
I have this code:
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Date;
public class EmployeeProcessor {
public static void main(String[] args) {
Employee employee = new Employee();
employee.lastName = "Smith";
employee.firstName = "Adam";
employee.id = 123456789;
employee.salary = 50000;
try(FileOutputStream fileOutStr = new FileOutputStream("Employee.ser");
ObjectOutputStream objectOutStr = new ObjectOutputStream(fileOutStr)) {
objectOutStr.writeObject(employee);
System.out.println("An employee is externalized into the file Employee.ser");
} catch (IOException ioError){
ioError.printStackTrace();
}
}
}
But in Intellij IDEA ObjectOutputStream class is strikethrough Like this:
screenshot. When pointing mouse pointer over - this message appears: 'java.io.ObjectOutputStream' is deprecated. What does it mean?
When I run this code, IntelliJ opens "Edit Configurations" windows asking me to introduce VM options. But I leave it blank and run anyway.
IntelliJ IDEA has an intention action to annotate library classes as Deprecated using the External Annotations support. You've probably triggered this intention action by accident.
For the classes deprecated this way there supposed to be the reverse action: Deannotate, but it may not work (bug reported).
To fix it manually, find the annotations.xml file in a directory that is configured in the SDK Annotations tab and edit/remove it.
UPDATE: Deannoate action should work now, but only while inside the annotated class itself, not from its reference.
I am trying to use a custom formatter to turn a boolean into "Yes" or "No" and have run into a roadblock.
My IDE (Eclipse) does not indicate any errors but when I try to compile I receive
[ERROR] Annotation error: cannot resolve foobar.client.formatter.YesNoFormatter - exception: ClassNotFoundException
followed by a few other exceptions that appear to stem from this exception. I understand what a ClassNotFoundException indicates however I cannot figure out why I would be getting it since, as my code shows, the YesNoFormatter class is located in foobar.client.formatter and I can access it through
GWT.log("True: " + YesNoFactory.getFormat().format(Boolean.TRUE);
I am using GXT 3.1.0 and GWT 2.6.1.
Could anybody have an idea of why I am getting this exception? The example given at http://docs.sencha.com/gxt-guides/3/utility/xtemplates/XTemplates.html doesn't mention anything (as far as I can see) about these classes needing to be in specific locations so I am at a loss.
EntryPoint:
package foobar.client;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.sencha.gxt.core.client.XTemplates.FormatterFactories;
import com.sencha.gxt.core.client.XTemplates.FormatterFactory;
public class TestClass implements EntryPoint {
#FormatterFactories(#FormatterFactory(factory=YesNoFactory.class, name="yesNo"))
public interface Renderer extends XTemplates {
#XTemplate(source="yesNo.html")
SafeHtml render(Boolean b);
}
#Override
public void onModuledLoad() {
GWT.log("True: " + YesNoFactory.getFormat().format(Boolean.TRUE);
Renderer r = GWT.create(Renderer.class);
Window.alert(r.render(true).asString());
}
}
YesNo:
package foobar.client.formatter;
import com.sencha.gxt.core.client.XTemplates.Formatter;
public class YesNo implements Formatter<Boolean> {
#Override
public String format(Boolean data) {
if (data == null) {
return null;
}
return (data) ? "Yes" : "No";
}
}
YesNoFactory:
package foobar.client.formatter;
public class YesNoFactory {
public static YesNo getFormat() {
return new YesNo();
}
}
in foobar
<?xml version="1.0 encoding="UTF-8"?>
<module>
<inherits name='com.google.gwt.user.User'/>
<inherits name='com.sencha.gxt.GXT'/>
<entry-point class='foobar.client.TestClass'/>
<source path='client'/>
</module>
foobar/client/yesNo.html:
{b:yesNo()}
My formatter classes (YesNo and YesNoFactory) apparently have to be in a location that gets compiled prior to compiling the client-side code. After I moved these classes to my 'shared' package - the package that houses code used by the client and server - everything worked.
This was not obvious in the XTemplates portion of the guide at http://docs.sencha.com/gxt-guides/3/utility/xtemplates/XTemplates.html which does not seem to specify where the files used for custom formatters need to be located. Maybe that should have been obvious but not to me.
I'm trying to load JRuby dynamically at runtime (so I can execute Ruby code using arbitrary JRuby installations and versions). My plan is roughly to create a ClassLoader that has access to jruby.jar, then use that to load the necessary JRuby runtime etc. All was well until I needed to do this multiple times. If I destroy the first JRuby runtime, the third or fourth will cause an OutOfMemory: PermGen space.
I've reduced this to a minimal example. The example uses both the "direct" API as well as the JRuby Embed API. The "direct" API section is commented out, but both exhibit the same behavior: after a few iterations, PermGen is out of memory. (tested with JRuby 1.6.7 and JRuby 1.6.5.1)
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import org.junit.Test;
public class JRubyInstantiationTeardownTest {
#Test
public void test() throws Exception {
for (int i = 0; i < 100; ++i) {
URL[] urls = new URL[] {
new URL("file://path/to/jruby-1.6.7.jar")
};
ClassLoader cl = new URLClassLoader(urls, this.getClass().getClassLoader());
// "Direct" API
/*
Class<?> klass = cl.loadClass("org.jruby.Ruby");
Method newInstance = klass.getMethod("newInstance");
Method evalScriptlet = klass.getMethod("evalScriptlet", String.class);
Method tearDown = klass.getMethod("tearDown");
Object runtime = newInstance.invoke(null);
System.out.println("have " + runtime);
evalScriptlet.invoke(runtime, "puts 'hello, world'");
tearDown.invoke(runtime);
*/
// JRuby Embed API
Class<?> scriptingContainerClass = cl.loadClass("org.jruby.embed.ScriptingContainer");
Method terminate = scriptingContainerClass.getMethod("terminate");
Method runScriptlet = scriptingContainerClass.getMethod("runScriptlet", String.class);
Object container = scriptingContainerClass.newInstance();
System.out.println("have " + container);
runScriptlet.invoke(container, "puts 'hello, world'");
terminate.invoke(container);
}
}
}
Questions: is this a reasonable thing to try to do with a ClassLoader? If so, is this a bug in JRuby, or am I doing something wrong with my class loading?
Bonus: if this were a bug in JRuby, how might something like Eclipse Memory Analysis tool help find the source? I can open a heap dump and see several Ruby objects (where I'd expect no more than one at any given time), but I'm not sure how to find why these aren't being garbage collected...
Try to look at stackoverflow: loading classes with different classloaders to unload them from the JVM when not needed and references from there. Sources of a mature web-container (like Tomcat) should have answers for your problem somewhere in load/unload stack.
PermGen stores bytecode for loaded classes (and generated dynamic proxies). It should be properly compacted by GC, when all references to the classes and their class loader cleared. But your code proves that something keeps your JRuby classes locked and accessible from the main class loader. It could be callback map of somekind the JRuby registers itself on load.
Edit: reported this as a bug: JRUBY-6522, now fixed.
After digging around in the Eclipse Memory Analyzer, I clicked "path to GC" on one of the URLClassLoader instances. It was referenced by org.jruby.RubyEncoding$2 which was referenced by java.lang.ThreadLocal$ThreadLocalMap$Entry.
Looking inside that source file, I see a static ThreadLocal variable being created: RubyEncoding.java:266. ThreadLocals are presumably hanging around forever, referencing my ClassLoader and leaking memory.
This code example succeeds:
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
public class JRubyInstantiationTeardownTest {
public static int i;
#Test
public void test() throws Exception {
for (i = 0; i < 100; ++i) {
URL[] urls = new URL[] {
new URL("file:///home/pat/jruby-1.6.7/lib/jruby.jar")
};
final ClassLoader cl = new URLClassLoader(urls, this.getClass().getClassLoader());
final Class<?> rubyClass = cl.loadClass("org.jruby.Ruby");
final Method newInstance = rubyClass.getMethod("newInstance");
final Method evalScriptlet = rubyClass.getMethod("evalScriptlet", String.class);
final Method tearDown = rubyClass.getMethod("tearDown");
// "Direct" API
Callable<Void> direct = new Callable<Void>() {
public Void call() throws Exception {
// created inside thread because initialization happens immediately
final Object ruby = newInstance.invoke(null);
System.out.println("" + i + ": " + ruby);
evalScriptlet.invoke(ruby, "puts 'hello, world'");
tearDown.invoke(ruby);
return null;
}
};
// JRuby Embed API
final Class<?> scriptingContainerClass = cl.loadClass("org.jruby.embed.ScriptingContainer");
final Method terminate = scriptingContainerClass.getMethod("terminate");
final Method runScriptlet = scriptingContainerClass.getMethod("runScriptlet", String.class);
// created outside thread because ruby instance not created immediately
final Object container = scriptingContainerClass.newInstance();
Callable<Void> embed = new Callable<Void>() {
public Void call() throws Exception {
System.out.println(i + ": " + container);
runScriptlet.invoke(container, "puts 'hello, world'");
terminate.invoke(container);
return null;
}
};
// separate thread for each loop iteration so its ThreadLocal vars are discarded
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(direct).get();
executor.submit(embed).get();
executor.shutdown();
}
}
}
Now I'm wondering if this is acceptable behavior of JRuby, or what JRuby-Rack does in the context of a servlet container where the servlet container is managing its own thread pool to process requests. It seems like one would need to maintain a completely separate thread pool, only execute Ruby code in those threads, and then ensure they get destroyed when the servlet is undeployed...
This is very relevant: Tomcat Memory Leak Protection
See also JVM bug report: Provide reclaimable thread local values without Thread termination