Ignore Varargs Warnings In Javac - ant

I want to escalate the missing serialversionUID warning to an error and fail my build when it occurs in javac.
I have added the following to my ant task:
<compilerarg value="-Xlint:serial"/>
<compilerarg value="-Werror"/>
However, the build also fails with varargs warnings:
non-varargs call of varargs method with inexact argument type for last parameter;
cast to java.lang.Object for a varargs call
cast to java.lang.Object[] for a non-varargs call and to suppress this warning
I tried changing the javac task to
<compilerarg value="-Xlint:-varargs"/>
<compilerarg value="-Xlint:serial"/>
<compilerarg value="-Werror"/>
However, it made no difference. How do I make the compiler ignore these warnings and only fail on the serialversionUID?
I am using Ant 1.9.4 and tried with Javac 1.6u37, 1.7u79 and 1.8u92
Example class:
package com.stackoverflow.compiler;
import java.io.Serializable;
public class Main implements Serializable {
public static void foo(Object... args) {
System.out.println("Test foo");
}
public static void main(String[] args) {
// is args supposed to be an array of objects
// or the only element in an array?
foo(args);
}
}

It seems that the warning you have is not related to the -Xlint:varargs option
According to javac reference the varargs option for -Xlint:
Warns about unsafe usages of variable arguments (varargs) methods, in particular, those that contain non-reifiable arguments
The documentation says that the following code:
public class ArrayBuilder {
public static <T> void addToList (List<T> listArg, T... elements) {
for (T x : elements) {
listArg.add(x);
}
}
}
should produce the warning:
warning: [varargs] Possible heap pollution from parameterized vararg type T
The actual warning I get (using javac 1.8.0_65) is:
warning: [unchecked] Possible heap pollution from parameterized vararg type T
(i.e unchecked instead of varargs)
The warning you got can be caused by code like this:
public static void foo(Object... args) {...}
public static void main(String[] args) {
// is args supposed to be an array of objects
// or the only element in an array?
foo(args);
}
That warning went away only using -Xlint:none option, but then -Xlint:serial does nothing. So it seems what you want is not possible.

I know the question is about javac, but let me still mention that ecj can be configured to meet your requirement: simply say -err:serial on the command line.
With that option this source file
public class Serial implements java.io.Serializable {}
will trigger this compiler output
----------
1. ERROR in /tmp/Serial.java (at line 1)
public class Serial implements java.io.Serializable {}
^^^^^^
The serializable class Serial does not declare a static final serialVersionUID field of type long
----------
1 problem (1 error)
Other warnings are not affected by that option. In particular, you could complete suppress the varargs warning by adding -warn:-varargsCast. This isn't necessary because a warning will never let your build fail. But if you really don't want to see this even as a warning, the full command line would look like this:
ecj -err:serial -warn:-varargsCast Main.java
See the JDT FAQ for using ecj in automated builds, incl. ant.

Related

Dart method types doing odd things

I have the following Dart code:
void main() {
provide(1, 'A');
}
void provide<A>(A one, A two) {
print('one $one two $two');
}
In java the call to provide will give a compile time error as the two parameters should be both of type A. With java as soon as you pass an argument to a typed parameter that defines the type.
My understanding is that with Dart if I don't follow 'provide' with a type then the type is dynamic.
To get the above code to work correctly in dart I have to write:
void main() {
provide<int>(1, 'A');
}
void provide<A>(A one, A two) {
print('one $one two $two');
}
This will now give a compile type error as 'A' is not an int.
This however is error prone as the user is likely to forget to add the type when callng provide.
Is there anyway I can make calls to the provide method type safe without having to write provide<int>(....
I've trivialised the example, the aim is to make a call to a method such as :
void provide(Token<T> token, T value);
If T is not the correct type then the user should get a compile error.

Dart - implementing a class method with argument as implemented class

I am developing external library. Assume I have different implementations of logger class, I create abstract class ILogger which those classes can then implement.
I also have various implementations of log objects that I want to adhere to ILog abstract class so I expose it as well.
The problem is when my ILogger uses ILog as argument to one of its methods. I would assume that any of my implemented logger classes (that implement ILogger) would accept any arguments that are log classes (which implement ILog).
See my constrained example below:
abstract class ILog {
const LogImpl({required this.id});
final String id;
}
class Log implements ILog {
const Log({required this.id});
final String id;
}
abstract class ILogger {
void writeLog({
required LogImpl log,
required bool persist,
});
}
class Logger implements ILogger {
void writeLog({
required Log log,
required bool persist,
}) {
print('writing $log with persistence? $persist');
}
}
void main() {
final logger = Logger();
final log = Log(id: 'abcd-1234');
logger.writeLog(log: log, persist: true)
}
For this I get error:
Error: The parameter 'log' of the method 'Logger.writeLog' has type 'Log', which does not match the corresponding type, 'ILog', in the overridden method, 'ILogger.writeLog'.
Is there a way to solve this without resorting to applying generics?
The reason why my log object ILog needs to be abstract class instead of regular class that is extended is technical. One of my serialization libraries uses source code annotation which means that this annotation cannot be part of the library (because the annotation might be different for different applications).
The program doesn't compile because it's not sound.
Dart, and object oriented programming in general, is based around subtype substitutability. If your code works with an instance of a type, it works with an instance of a subtype too - the subtype can substitute for the supertype.
The Logger's writeLog method is not a valid override of the ILogger's writeLog method. The latter accepts an ILog as argument, and for the subtype to be able to substitute for that, it needs to accept an ILog too. However, it only accepts a Log, which is a subtype, and not any implementation of ILog.
One alternative is to admit that what you are writing is unsound, and tell the compiler to accept it anyway:
class Logger implements ILogger {
void writeLog({
required covariant Log log,
required bool persist,
}) {
print('writing $log with persistence? $persist');
}
}
Here the covariant tells the compiler that you know that Log does not satisfy the superclass parameter type of ILog, but it's OK. You know what you're doing, and no-one will ever call this function with something which isn't a proper Log. (And if they do anyway, it'll throw an error).
The other alternative, which is what I'd probably recommend, is to parameterize your classes on the Log it uses:
abstract class ILogger<L extends ILog> {
void writeLog({
required L log,
required bool persist,
});
}
class Logger implements ILogger<Log> {
void writeLog({
required Log log,
required bool persist,
}) {
print('writing $log with persistence? $persist');
}
}
With that, the Logger doesn't have to substitute for all ILoggers, only for ILogger<Log>, and it can do that soundly.
(Well, as soundly as the inherently unsound covariant generics allow, but the program will compile, and throw if you ever pass something which isn't a Log instance.)
In both cases the compiler will know that the argument to a Logger must be a Log. In both cases, you can fool the program by casting the Logger to the supertype ILogger/ILogger<ILog>, and then pass in an ILog to writeLog, but it takes at least a little effort to circumvent the type system.

What is the difference of the anonymous internal class directly call the external class instance method in the OpenJDK and Oracle? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Today, I reviewed same Android code, and found a strange phenomenon.
It is the anonymous internal class directly called the external class instance method.
In my mind, directly calling a method is equivalent to adding this directly before the method, and this is an instance of an inner class.
According to this logic, an instance of an external class is invoked directly in the anonymous inner class, that will caused the compile ERROR.
But actually compile this application, and no problem. And the running log is normal.
Therefore, writing a simple Demo to verify the previous concept is wrong. code show as below:
public class InnerClass {
public static void main(String[] args) {
new InnerClass().process();
}
public void process() {
new Thread() {
#Override
public void run() {
System.out.println(toString("test"));
}
}.start();
}
public String toString(String string) {
return string;
}
}
In the Oracle:
In the OpenJDK:
So, What is the difference of the anonymous internal class directly call the external class instance method in the OpenJDK and Oracle?
Where can I find documentation to see these differences?
I worked hard, but did not get a clear answer.
Thanks.
P.S.
In According to my point of view
public class InnerClass {
public static void main(String[] args) {
new InnerClass().process();
}
public void process() {
new Thread() {
#Override
public void run() {
// In According to my point of view
// toString("test")
// <==>
// this.toString("test")
// and `this` is the instance of Thread
// what's the error of my view?
System.out.println(toString("test"));
}
}.start();
}
public String toString(String string) {
return string;
}
}
The problem is that
public void run() {
System.out.println(toString("test"));
}
is calling toString on the anonymous Thread subclass, and that is Thread::toString(). There is no Thread::toString(String), and the toString(String) method from the enclosing scope is not considered.
The JLS states that it will only check an enclosing / outer class for a method if there is no method with the required name in the inner class. See JLS 15.12.1:
If the form is MethodName, that is, just an Identifier, then:
If the Identifier appears in the scope of a visible method declaration
with that name (§6.3, §6.4.1), then:
If there is an enclosing type declaration of which that method is a member, let T be the innermost such type declaration. The class or
interface to search is T.
This search policy is called the "comb rule". It effectively looks for methods in a nested class's superclass hierarchy before looking
for methods in an enclosing class and its superclass hierarchy. See
§6.5.7.1 for an example.
As to why OpenJDK Java 7 accepts your test class .... if that is actually true, I'd call that a compiler bug. But it would be a general Java 7 bug not an OpenJDK specific one. The javac codebases are (AFAIK) identical for Oracle and OpenJDK releases of the same version.
Interestingly, I have a copy of Oracle Java 6, and javac from that version also calls this a compilation error as well.
$ /usr/java/jdk1.6.0_45/bin/javac InnerClass.java
InnerClass.java:10: cannot find symbol
symbol: method toString(java.lang.String)
System.out.println(toString("test"));
^
1 error
So ... maybe ... you should rerun your OpenJDK Java 7 test, and make sure you are compiling the same source code!

Exception in thread "main" java.lang.Error: Unresolved compilation problems: JNI4net

I am working with JNI4net and although the libraries and installed in the build path and eclipse recognizes them, it still gives me run time error. Why could that be in your opinion? Here is the code.
import net.sf.jni4net.*;
import java.io.IOException;
import java.lang.String;
import system.*;
import system.Object;
import system.io.TextWriter;
import system.collections.IDictionary;
import system.collections.IEnumerator;
/**
* #author Pavel Savara (original)
*/
public class Program {
public static void main(String[] args) throws IOException {
// create bridge, with default setup
// it will lookup jni4net.n.dll next to jni4net.j.jar
//Bridge.setVerbose(true);
Bridge.setVerbose(true);
Bridge.init();
// here you go!
Console.WriteLine("Hello .NET world!\n");
// OK, simple hello is boring, let's play with System.Environment
// they are Hashtable realy
final IDictionary variables = system.Environment.GetEnvironmentVariables();
// let's enumerate all keys
final IEnumerator keys = variables.getKeys().GetEnumerator();
while (keys.MoveNext()) {
// there hash table is not generic and returns system.Object
// but we know is should be system.String, so we could cast
final system.String key = (system.String) keys.getCurrent();
Console.Write(key);
// this is automatic conversion of JVM string to system.String
Console.Write(" : ");
// we use the hashtable
Object value = variables.getItem(key);
// and this is JVM toString() redirected to CLR ToString() method
String valueToString = value.toString();
Console.WriteLine(valueToString);
}
// Console output is really TextWriter on stream
final TextWriter writer = Console.getOut();
writer.Flush();
}
}
AND here is the message I get!
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
Bridge cannot be resolved
Bridge cannot be resolved
Console cannot be resolved
IDictionary cannot be resolved to a type
system cannot be resolved
IEnumerator cannot be resolved to a type
system cannot be resolved to a type
system cannot be resolved to a type
Console cannot be resolved
Console cannot be resolved
Console cannot be resolved
TextWriter cannot be resolved to a type
Console cannot be resolved
at Program.main(Program.java:37)
To make your life easier, I am going to share my findings here. Read Martin Serrano's answer to my question. It will help you understand what needs to be done. Then go to jni4net's website and download their example zip folder. Extract that. There is an example there called myCSharpDemoCalc. Replace your dll with myCSharpDemoCalc.dll (inside work folder) and then run generateProxies.cmd (be sure to edit this file to your dll name) and run.cmd. Then go to the work folder and run build.cmd (edit name) to create your JAR file. It might not spit out the j4n.dll you probably need to twik the path yourself. Use this JAR file. This was the easiest way to create a JAR file from a third party dll for me.

error while compiling java program

I am compiling my java program,but i got stuck at one point.
whenever i am seeting classpath from command window i am getting an error
D:\Project\D1>set path=%path%;C:\Program Files\Java\jdk1.7.0_45\bin;
D:\Project\D1>javac hello.java
hello.java:3 error:cannot find symbol
public static void main(string arg[])
symbol:class string
location:class hello
hello.java:5: error:package system does not exist
system.out.println("hello");
2 errors
I am not getting what type of error is this.
Please help me to resolve this error
Just to give a clarity on Java standards,
In Java all the class names starts with Caps letter and followed by camel casing.
So in your case you are trying to access two classes,
String and System - These should be used with caps cases.
so
public static void main(String args[])
and
System.out.println("hello");
should resolve the issue.
It will be great if you change your class name as Hello.
That is a good start in Java and welcome to Java community.
string is not a class in Java. However, String is the correct class. Java is case-sensitive!
Your main method should look like:
public static void main(String args[])
Also, System is the correct class:
System.out.println("hello");
Entire method:
public static void main(String args[])
{
System.out.println("hello");
}

Resources