I have an application that I've been trying to get working with Java 8's RMI. I'm using eclipse Neon.3 on Windows 10 and it is complaining that I am not implementing methods of an interface that don't exist. In trying to narrow down a separate issue, I've commented out one of the abstract methods of the interface.
After commenting out the one abstract method, the interface is then exported to a jar file; the jar file is then added to the build path of the server application that will implement the interface.
The interface:
package accessService;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.HashMap;
public interface ApplicationAccessService extends Remote{
//public void connectClient(Long[] clientId) throws RemoteException;
public HashMap<String, Long> getClientConnections() throws RemoteException;
public HashMap<String, Integer> getServerConnections() throws RemoteException;
}
The implementing class:
package iap.util;
import java.rmi.RemoteException;
import java.util.HashMap;
import accessService.ApplicationAccessService;
public class RemoteIAP implements ApplicationAccessService{
private final static HashMap<String, Integer> SERVERS = new HashMap<>();
private final static HashMap<String, Long> CLIENTS = new HashMap<>();
public RemoteIAP(){ }
//methods used by RMI interface--------------------------------------
#Override
public HashMap<String, Integer> getServerConnections() throws RemoteException {
return SERVERS;
}
#Override
public HashMap<String, Long> getClientConnections() throws RemoteException {
return CLIENTS;
}
//end RMI methods-------------------------------------------------------
}
The error:
The type RemoteIAP must implement the inherited abstract method ApplicationAccessService.connectClient(Long[])
It seems to me, that eclipse is somehow maintaining artifacts from before commenting out the method in question. Restarting eclipse and rebooting my pc has done nothing to change this behavior. I don't know if this is a problem with java, the manner I'm adding the interface to the build path using the context menu's in eclipse, or something else?
Sometimes, ide can read the old compiled .class file and somehow it does not replace with the new one after the build operation.
Change the class name and build again.
I think it's possible that taking out the line and then exporting may have failed. Understand that in the .jar, it is the code in the compiled .class file that matters, not in the .java file. So if you hadn't recompiled before exporting, you could have an old version in the .jar
Related
This might be a dumb question, but somehow i am unable to crack it.
I have create a maven project(Project 1) and defined a public method. I have created the jar(foo.jar) file using mvn verify.
package com.aaa.bbb;
public class FooClass{
public void fooMethod(){
System.out.print("Hello World");
}
}
In another project(Project 2) i added this jar in Eclipse configure build path -> libraries.
I cleaned this project and updated it.
When i wanted to access FooClass and its method it is saying FooClass cannot be resolved as type.
package com.iii.jjj;
import com.aaa.bbb; //Throwing an error saying the import com.aaa.bbb cannot be resolved
public class TestClass{
public void printMsg(){
FooClass obj=new FooClass(); //throwing error here FooClass cannot resolved to a type
}
}
But when i create another class extends FooClass, it is properly identifying.
package com.iii.jjj;
public class TestClass2 extends FooClass{ //It is working fine here
}
Tried different solutions, but no luck yet. Can someone help?
I would like to be able to add a file with the java structure and extension into my program to an arraylist via outside the actual program directory/jar.
Ex,
Test.java, located at C:\Users\user\Desktop\Test.java (Outside the jar)
public class Test extends Object {
public Test() {}
public void someMethod() {}
}
MyProgram.java
import java.util.ArrayList;
public class MyProgram extends Object {
public MyProgram() {}
public void readIn() {
ArrayList<Object> list = new ArrayList<Object>();
list.add(Test.java);
}
}
Obviously a lot more will have to be done but hopefully you understand the point.
Read In Test.java -> Convert it somehow so it's added to the arraylist due to it's extension. So if the extension was Family instead of Object, the arraylist would be ArrayList instead and Test extends Family.
Edit
As stated by a comment, this is an approach to a plugin mechanism.
The answer to this question stems from Seelenvirtuose's suggestion along with crick_007. To access classes outside the class path, simply create a ClassLoader and load the class in.
You must also use an interface to interact between the two classes, also knowing what methods are provided. Lastly, packaging must also be the same or else you'll get errors such as
PACKAGENAME.CLASS cannot be cast to PACKAGENAME.CLASS even if the class has the same name as in your program (A test I tried)
I thought I would use the new ResourceBundleControlProvider framework in Java 8 to fix something which Oracle themselves will never fix - the default encoding used when reading resource bundles.
So I made a control:
package com.acme.resources;
import java.io.IOException;
import java.util.Locale;
import java.util.ResourceBundle;
public class AcmeResourceBundleControl extends ResourceBundle.Control
{
#Override
public ResourceBundle newBundle(String baseName, Locale locale, String format,
ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException
{
throw new UnsupportedOperationException("TODO");
}
}
Then I made a provider:
package com.acme.resources;
import java.util.ResourceBundle;
import java.util.spi.ResourceBundleControlProvider;
public class AcmeResourceBundleControlProvider implements ResourceBundleControlProvider
{
private static final ResourceBundle.Control CONTROL = new AcmeResourceBundleControl();
#Override
public ResourceBundle.Control getControl(String baseName)
{
if (baseName.startsWith("com.acme."))
{
return CONTROL;
}
else
{
return null;
}
}
}
Then in META-INF/services/java.util.spi.ResourceBundleControlProvider:
com.acme.resources.AcmeResourceBundleControlProvider
Then I just tried to run our application from IDEA and I find that it never loads my provider (otherwise the exception would be raised.)
I have checked the names and they all seem to match up. I have checked the compiler output directory IDEA is using and it does contain the service file. I wrote a simple test program which just tries to look up the service:
public static void main(String[] args)
{
for (ResourceBundleControlProvider provider :
ServiceLoader.load(ResourceBundleControlProvider.class))
{
System.out.println(provider.getClass());
}
}
This does print out one entry which is the name of my implementation class. So the issue is not in the service file.
If I breakpoint inside ResourceBundle, I seem to be able to access the custom provider class. Initial forays into the debugger show that ServiceLoader isn't finding any implementations, but I can't figure out why. I'm sure there is some dodgy class loader magic going on which results in not loading my class. :(
Some scary documentation on the Javadoc makes it sound like it might have to be installed as a global extension. If that really is the case, it's a bit of a shame, because it seemed like a useful way to override the default (and in my opinion broken) behaviour. But I also read the tutorial on the matter and it didn't seem to be describing anything like that (unless the good behaviour was pulled out of Java 8 at the very last minute and the docs are out of date!)
The tutorial does state that the JAR containing the ResourceBundleControlProvider must be in the JVM's system extension directory. Section 6 of the tutorial describes the requirement:
java -Djava.ext.dirs=lib -cp build RBCPTest
When you install a Java extension, you typically put the JAR file of the extension in the lib/ext directory of your JRE. However, this command specifies the directory that contains Java extensions with the system property java.ext.dirs.
The JavaDoc for ServiceLoader.loadInstalled() also states that providers on the application's class path are ignored.
Your problem is that the java.util.ResourceBundle that comes with the JVM does a ServiceLoader.loadInstalled(ResourceBundleControlProvider.class) to obtain a list of providers in the static initializer, and uses the thus obtained list ever after.
Is that possible to give custom warning message in my own API like below? Is Resource leak:'ois' is never closed message related with Java API or JVM?
It's possible using a compiler API. You have to extend an AbstractProcessor and then make sure compiler knows about it.
Lets say we don't like programmers to swear in the source code. So, when someone defines a field with name "shit", we want to show a warning. Here is a simple implementation:
import java.util.List;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;
#SupportedSourceVersion(SourceVersion.RELEASE_7)
#SupportedAnnotationTypes("*")
public class Test extends AbstractProcessor {
public int shit;
public int foo;
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Set<? extends Element> rootElements = roundEnv.getRootElements();
for (Element element : rootElements) {
if (element.getKind() == ElementKind.CLASS) {
List<? extends Element> classElements = element.getEnclosedElements();
for (Element classElement : classElements) {
if (classElement.getKind() == ElementKind.FIELD) {
if (classElement.getSimpleName().contentEquals("shit")) {
processingEnv.getMessager().printMessage(
Kind.WARNING,
"How dare you to swear in the source code?!",
classElement
);
}
}
}
}
}
return false;
}
public static void main(String[] args) {
//
}
}
Now, we want to apply such a processor just for this very class, because there is an ugly bad-called field too.
Using a command line:
javac Test.java
javac -processor Test Test.java
We need to firstly build a processor and then apply it while compiling (in this case to the same file).
And this is the output we get:
Test.java:17: warning: How dare you to swear in the source code?!
public int shit;
^
1 warning
To have the same warning in Eclipse or any other IDE, it's necessary to change compiler settings so it uses this custom processor.
Update: In the comments, kapep sent a link on how to set a custom processor in Eclipse: http://kerebus.com/2011/02/using-java-6-processors-in-eclipse/
Just for the record: Exactly the same warning may be achieved by implementing interface Closeable:
import java.io.Closeable;
import java.io.IOException;
public class Test implements Closeable {
#Override
public void close() throws IOException {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
new Test();
}
}
And you see the same warning:
You can create warnings, notes, errors and other diagnostic messages like this using an annotation processor. It's a compiler plugin api integrated in the JDK. It lets you analyse the outline structure of source code. Despite the name you don't really need to handle any annotation when processing code. Messages are created using the Messager class. If you provide an element, it will be marked and the message will be shown next to it in the source code editor.
You won't be able to show message on elements inside methods or expressions though, only on declarations like types, properties, methods or parameters. It's possible to additionally parse the method body and generate messages based on the content using other tools, but as far as I know you can't show the message on the actual local element then. You could still show the message on the enclosing method or don't specify any element at all and show it in the IDE's log.
The IDE also needs to support this. I know that Eclipse and NetBeans do support messages generated by annotation processors, but there are probably other modern IDE that do so as well. If you need more features like messages on elements inside method bodies or the quick fix feature as shown in the example, I guess you need to create a plugin for the IDE.
I would believe that it is related to the eclipse ide, you could possibly write a plugin which displays warnings like that.
For example, when you use a method which has the annotation '#Deprecated' the ide automatically tells the programmer that the method is deprecated.
I am staring to learn about RMI in java and I am using Netbeans 7.0.1. I created a basic interface
package helloclass;
import java.rmi.*;
public interface HelloInterface extends Remote
{
public String hello() throws RemoteException;
}
This is the class that implements the interface
package helloclass;
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
public class HelloClass extends UnicastRemoteObject implements HelloInterface
{
private String message;
public HelloClass() throws RemoteException{}//constructor throwing RemoteException
public String hello() throws RemoteException //method throwing RemoteException
{
return "Saying hello";
}
public static void main(String[] args)
{
}
}
In my understanding I now need to build these two classes and then run the rmic command in the command prompt.
How do I run this rmic command in the command prompt using netbeans?.
I have been trying by going to Project Properties and then typing rmic in the VM options at the Run after specifying the directory where HelloClass.class is located but it can't seem to find the class.
As of Java 5 there is no need to use the rmic command for generating stubs, they will be generated dynamically for you, check this
However, if you still want to support clients running on earlier version, run the command from the base directory of the compiled classes (in your case the directory that contains the "helloclass" directory) and use the class qualified name, e.g.: rmic helloclass.HelloClass