I have an EJB returning a list of my own ValidationMessage objects:
#Remote
public interface Intf {
List<ValidationMessage> validateFile();
}
I'm generating EJB client JAR with weblogic's appc utility. The problem is that it does not include ValidationMessage class into the client JAR. Perhaps it does not see the dependency to this class because it only looks at the compiled code, when generic information is already erased.
If I add another dummy method, which returns this class directly, to the interface, everything is fine.
#Remote
public interface Intf {
List<ValidationMessage> validateFile();
ValidationMessage dummy();
}
My question is: is there a way to fix this without adding a dummy method? Is there a way to control what gets included by appc in the client JAR?
This is not and actual answer and I have no knowledge of WebLogic or the appc utility.
That looks like a generics erasure problem. The actual return type from the validateFile() method is the raw type List; while there is extra info in the classfile to reconstruct the type parameters, some tools do not check them.
I'm predicting that this problem will go away if you also reference the missing class in a method parameter.
I did get a simialr problem with appc where i wanted to override some of the POJOS it generated for JAX-WS client.
I used this option (-output) to generate the output to a exploded directory instead of a client jar.Do an ant copy of your required .class files to the client directory and create a jar of your own.
You can see this option if you do 'java weblogic.appc' execute setEnv.cmd
-output Specifies an alternate output archive or
directory. If not set, output will be
placed in the source archive or directory.
check if this works
Related
I have two jars. One provides a service interfaces and a service loading class and one provides the implementation of that service.
This works perfectly when running this in jdk8, but I get an service type not accessible to unnamed module #3754a4bf error when running on jdk9 or higher.
I migrated that two jars to a module base jar and that works great when running on >= jdk9, but that fails on jdk8 of cause, because of wrong class file version.
So, I don't have problem using java serivceloader api with java 8 or 9.
I'm aware of https://blog.codefx.org/tools/multi-release-jars-multiple-java-versions/ , but I want to avoid to make the build process more complicated. The build already involves class relocation and
other stuff.
My question: Is there a way to use the same jars running on jdk8 and >=jdk9 using java serviceloading api?
In JDK9 and up, all jars are effectively 'modules'. If they do not have a module definition (which you create by making a file named module-info.java and putting a module declaration inside), its name is 'unnamed module #whatever', it exports all its packages, and can access anything exported by any other module (in module-speak: it 'reads' everything). Meaning, if all your classpath dependencies are such unnamed modules, they all export everything and they all read everything thus they all can access anything marked public from anybody else – which is how it worked in JDK8, and thus, why it's all compatible.
To be clear: in JDK9, for code in module (jar) A to access a method, class, or field from module (jar) B, then in addition to the usual access modifiers (the public keyword), B needs to 'export' that package, and A needs to read that module, or it doesn't work. If you aren't explicitly writing module info files for either side, well, then you get the default behaviour which is 'export everything' and 'read everything', bringing us back to the JDK8 scenario of: the thing has to be marked public, and then you can access it.
I actually do not recommend you make that module-info file; that's a big step, one you should only take once you're familiar with the module system.
The error means that the 'service type'[1] is not 'accessible'[2] to 'unnamed module #3754a4bf'[3]. Let's break that into pieces:
[1] serviceloader works by defining an interface that a 'service provider' implements, and the class using the service loader then ends up with a bunch of instances of that interface; each representing one implementation. It's the Foo in ServiceLoader.load(Foo.class).
[2] 'accessible' is module speak for: Either the code that needs this did not explicitly 'read' it, or the code that has this did not export it.
[3] 'unnamed module#3754abf' is the name of the module that is trying to access it.
Taking this all together, it means: You're operating under false assumptions: Whatever jar contains your service interface (that Foo I was talking about), is NOT an unnamed module, or, possibly, isn't public. Note that if it is a public interface inside a not-public class (i.e.: /* package private */ class Example { public interface MyServiceInterface {} }), that probably still counts as 'not public enough'.
If it's a named module (which means: it has a module-info.java file), then export the package that the service interface is in. See any jigsaw (the name of the java module system) tutorial on how to set that up. If it's not, ensure it's a public interface or abstract class, and if its inside some other type, make sure those are public too. If neither is the case, check your classpaths; javac is rather adamant that one of these two is the case.
I've already read the tutorial at ELKI documentation ( http://elki.dbs.ifi.lmu.de/wiki/Tutorial/DistanceFunctions ).
Unfortunately, I'm not grasping how to plug the generated .class with MiniGUI (or bash script for the provided .jar). How it can be done?
Ps: I know it sounds absolutely noob, but when I try to "type" the class name, as suggested, I get the error "The following parameters could not be processed: HammingDistance", for example.
ELKI will load classes via the standard Java Classloader. Therefore, they must be on the class path or they cannot be loaded. An example call (assuming your classes are in the bin folder) is java -cp elki.jar:bin/ de.lmu.ifi.dbs.elki.application.ELKILauncher
Parameters are interpreted as follows:
If there is a class with this name (including the package name!) it is used.
Otherwise, ELKI tries prepending the package name of the expected interface. Which enables shortcut names.
Otherwise, known classes (from the service files) are checked for aliases. For example, the Euclidean distance has an alias name of l2, Manhattan has an alias l1.
The class must have a parameterless public constructor or a inner public static class Parameterizer.
Input assistance is built as follows:
.jar files on the classpath are checked for service files in META-INF/elki/<interface>
folders on the classpath put you in development mode, where a recursive list is performed and all .class files are inspected. This is much slower, but removes the need to edit the service files. Discovered classes show up below the ones listed in the service file.
Furthermore, the package de.lmu.ifi.dbs.elki.application.internal includes classes that will inspect everything on your classpath, and will report e.g. classes that do not have a parameterless public constructor, or a inner public static class Parameterizer.
MATLAB is configured to search its static java class path before searching the user-modifiable dynamic path. Unfortunately, the static path contains quite a number of very old public libraries, so if you are trying to use a new version you may end up loading the wrong implementation and get errors.
For instance, the static path contains an old copy of the google-collections.jar, which has long been supplanted by Google's guava library and which has some of the same class names (e.g. com.google.common.base.Objects). As a result, if you invoke a Guava method that uses a newer method of one of such a class, you will end up getting surprising NoSuchMethodErrors because the google-collections jar is found first.
As of R2012b, MATLAB lets you specify additional jars to add to the static path by putting a javaclasspath.txt file in your preferences folder, but that adds jars to the end of the path, and doesn't let you override jars that are built into MATLAB.
So what is the best way around this?
I got an official response from Mathworks:
As of MATLAB R2013a (also in R2012b), classes can be added to the front of the static Java class path by including the following line in javaclasspath.txt:
<before>
Any directory that is after this line in javaclasspath.txt will be added to the front of the static Java class path. This is an undocumented use of javaclasspath.txt as of R2013a.
But overall in MATLAB, the ability to add classes to the front of the static Java classpath is not available through javaclasspath.txt in MATLAB 8.0 (R2012b).
MATLAB searches for classpath.txt in the following order:
In the startup directory. As of MATLAB 8.0 (R2012b) a warning will be shown if the file is found there and it will be ignored.
In the first directory on the MATLABPATH environment variable. (This environment variable is used in the bin/matlab shell script on Linux and in general is not used by the end-user).
In the toolbox/local directory.
Although the MATLABPATH environment variable of point 2 is normally not used by end-users we can use it in a workaround to allow reading a custom classpath.txt outside of the toolbox/local directory.
On Windows:
You will need to create the MATLABPATH environment variable. The first directory on it should be your directory with the custom classpath.txt AND you will also need to add the toolbox\local directory as second option. So from a cmd prompt you could do:
set MATLABPATH=c:\Users\user\Documents\myMATLABClasspath;c:\Program Files\MATLAB\R2012b
\toolbox\local
matlab.exe
One hack that appears to work is to add the jar to the top of the classpath.txt file that can be found in your MATLAB installations toolbox/local folder. Unfortunately, this is automatically generated and may get rewritten at some unspecified time, such as when you install new toolboxes, so this approach would require you to have some way to notice when this happens and reapply the hack.
If you're distributing a jar that's intended to be used with matlab, it may be better to use proguard as described at http://code.google.com/p/guava-libraries/wiki/UsingProGuardWithGuava.
If you specify that all of your classes and their (public) fields and methods are to be preserved and include guava as a program jar (not a library), then it will rename all of guava's methods and update your compiled bytecode to reference the new names.
It seems a bit hackish, but depending on the audience, it may be significantly easier than teaching your users about static vs. dynamic classpath, and it won't break any matlab code that depends on the old behavior.
Instead of obfuscating the package as suggested by #user2443532, I have found it easier to "shade" the conflicting package instead of obfuscating it - unless you actually need obfuscation. One easy way to do this is to build your package using Maven and use the maven-shade-plugin. Internal calls are modified automatically, so you don't need to modify any of the Java code.
Direct calls from Matlab will need to be modified - for example, calls to com.opensource.Class become shaded.com.opensource.Class.
For more info on shading, see What is the maven-shade-plugin used for, and why would you want to relocate Java packages?
I want to use a Java application, which is not written by me and also not maintained anymore, meaning I can't just go to the author and ask for a new feature. What options do I have to add proxy capabalities. Is it possible to add some shell arguments? Is it manageable work to add the binary code for the proxy directly into the .class file? Could I write my own class, import the stuff from the .class files and overwrite the network functionality?
This might work for you:
java -Dhttp.proxyHost=IP_address -Dhttp.proxyPort=8080 -jar App.jar
It is possible to replace a class with your own implementation by creating a class with the same name/package and placing it earlier in the classpath so it takes precedence. However you cannot break binary compatibility if this class is used by other parts of the code.
There are also instrumentation APIs available to modify classes as they are loaded. See the Instrumentation API.
If you are creating your own source file that references the compiled .class, then in your file try doing this:
java.util.Properties systemProperties = System.getProperties();
systemProperties.setProperty("http.proxyHost", PROXY_HOST);
systemProperties.setProperty("http.proxyPort", PROXY_PORT);
I think that should work.
I have an own annotation processor (let's call it MyProcessor) and a project (let's call it MyProject) which uses the processor by
passing -processor to javac.
Now I need MyProcessor to produce some output and make it available for MyProject.
I have following options (and problems):
Let MyProcessor write a file to the path, specified by the property user.dir.
Problem: from the point of view of MyProcessor, user.dir is always my home dir, not the path of MyProject.
Pass the current directory of MyProject to MyProcessor using javac's -A option.
Problem: It's an ugly hard-coded path: /some/path/to/MyProject/.
Let MyProcessor generate some source files, which then would be compiled by javac together with MyProject, so that MyProject can refer to this compiled class and retrieve data from it.
Problem: It's too complex for such an easy (?) task.
What other options are there?
Can someone please suggest, how to proceed?
Processor.init() method (which you've implemented) is invoked with ProcessingEnvironment as parameter which, in turn, has a getFiler() method returning a Filer instance.
You should be using the createResource() method of the Filer (assuming the output being generated is neither class nor source; otherwise use appropriate create method for that) and write your output to either class or source locations (former is probably preferable, but it depends on what you're doing). Both are overridable via command-line switches if need be, but are well-defined as they are to be used in a build process.