Re: Very fast List/Deque to java.util?

2022-06-11 Thread Rob Spoor
I'd like to point out that rodde has also asked this project to be 
included in Apache Commons Collections: 
https://lists.apache.org/thread/klwtkbz96rp9zfr1077sc9r8tjtthfl4



On 11/06/2022 15:53, - wrote:

Hello,


What do you think?


First, for your benchmarks, I recommend you write them with
https://github.com/openjdk/jmh, a library that allows configuration of
warmup time, number of trials, and has utilities that avoid jvm
optimization's impact on your benchmarks.

A few cents: I recall seeing a similar proposal before. This
implementation is definitely superior to the Linked List as an
implementation of both deque and list at the cost of an extra finger
array allocation, but it probably won't excel compared to dedicated
Deque or List implementations in terms of performance and memory
usage.

Modern JDK List/Deque users usually use the array-focused
implementations like ArrayDeque and ArrayList; even though ArrayList
is slow at adding or removing at non-tail, most usages of ArrayList is
iterating and sometimes adding (predominantly at tail). Array
iteration is better optimized by hardware due to arrays. Thus,
LinkedList is already out-of-favor like Vector, and there are relevant
discussions in https://github.com/openjdk/jdk/pull/2744. The
doubly-linked structure of the finger list is at a natural
disadvantage (for iteration) here.

Even though this finger list won't be a replacement for ArrayList or
ArrayDeque, I wonder if it can be modified to become a concurrent
collection, so that modifications to the list can be synchronized by
the intervals between fingers. If it can, it would probably provide an
efficient concurrent list implementation compared to the current
CopyOnWriteArrayList, even though your current implementation seems
not to support concurrency.


Does it deserve to be included in JDK?


Let's revisit your proposal again: if it's in the JDK, where will it
be used? After all, JDK is a library that is used by millions or
billions of programs. Feel free to come up with a few use cases and we
will see if this finger list is the best for those cases.

On Sat, Jun 11, 2022 at 2:39 AM Rodion Efremov  wrote:


Hi,

I have this List/Deque implementation that runs (in a rather versatile
benchmark) much faster than ArrayList and LinkedList:

https://github.com/coderodde/IndexedLinkedList

What do you think? Does it deserve to be included in JDK?

Best regards,
rodde




Re: RFR: 8287442: Reduce list to array conversions in java.lang.invoke.MethodHandles

2022-05-27 Thread Rob Spoor
On Fri, 27 May 2022 14:18:19 GMT, Claes Redestad  wrote:

> In preparation of #8855 this PR refactors the conversions from `List` to 
> array and array to `List`, reducing the number of conversions when calling 
> `MethodHandles.dropArguments` in particular. This remove about ~5% of 
> allocations on the `StringConcatFactoryBootstraps` microbenchmark.

src/java.base/share/classes/java/lang/invoke/MethodHandles.java line 5266:

> 5264:  */
> 5265: public static MethodHandle dropArguments(MethodHandle target, int 
> pos, List> valueTypes) {
> 5266: return dropArguments(target, pos, valueTypes.toArray(new 
> Class[0]).clone(), true);

Isn't this call to `clone()` unnecessary, as `valueTypes.toArray` should either 
return the passed empty array, or a newly created array?

-

PR: https://git.openjdk.java.net/jdk/pull/8923


Re: Type narrowing security leak

2021-12-30 Thread Rob Spoor
No it doesn't. It's still the same byte. However, the 0 to 255 range is 
for unsigned bytes, a type that does exist in some other language like 
C. In Java bytes are signed, so the same value is represented 
differently. However, both 200 (unsigned) and -56 (signed) represent the 
same binary value: 1100_1000.



On 30/12/2021 13:13, Fabrice Tiercelin wrote:

  Hi,

 Le mercredi 29 décembre 2021, 11:35:12 UTC+1, Rob Spoor 
 a écrit :

An example is
reading input streams byte-by-byte: the result is an int between 0 and > 255 
(inclusive), or -1 for EOF. If the result is not -1, the result is > almost always 
cast to a byte



Does your example mean that a whole virus can bypass an antivirus this way?
Fabrice


On 29/12/2021 07:43, Fabrice Tiercelin wrote:

Greetings,
Any Java application may be concerned by a hacker attack using a type narrowing 
leak. If a program does the following things in this order:
    - Assert that a numerical id is allowed - Do a type narrowing among other 
things, even followed by a type widening - Do an action with the numerical id
...the hacker can do forbidden actions. Let's say that a given user doesn't 
have rights to change an amount for the id 63:
public void changeAmount(long userId, double newAmount) throws 
IllegalArgumentException {  isUserIdAllowedOrThrowException(userId); // userId 
= 4294967359

     int theUserId = (int) userId; // theUserId = 63    userId = theUserId; // 
userId = 63
     doChangeAmount(userId, newAmount); // userId = 63
}
It will fail passing 63 but it will success passing 4294967359 because 
4_294_967_359 is narrowed into 63. Let's call 4_294_967_359  a rebound of 63. 
4294967359 can be retrieved in few seconds by a basic program like this:
public class MyClass {
       public static void main(String args[]) {
     long targettedNumber = 63;
 
     for (long rebound = Integer.MAX_VALUE + 1; true; rebound++) {  int typeNarrowing = (int) rebound;

     long typeWidening = typeNarrowing;
 
     if (typeWidening == targettedNumber) {

     System.out.println("Rebound for " + targettedNumber + " found: 
" + rebound);
     return;
     }
     }
       }
}
And it can be optimized. It works for any type narrowing. It not only works for 
numerical id but also for flags. If a numerical value should contain or not 
several flags, you can search a rebound among billions of rebounds until you 
find one with the perfect features. All the Java versions are concerned. The 
security layer can even be coded in another programming language.

To fix it, I suggest to add a test just before the type narrowing in the 
bytecode. The test verifies if the type narrowing will alter the numerical 
value. If true, it throws an unchecked exception or an error. Otherwise, it 
continues as currently. Note that it changes the behavior but the current 
behavior is dangerous, useless and is a failing case. You can add a compiler 
option to restore the original behavior but the new behavior should be the 
default.

Best regards,Fabrice TIERCELIN


Re: Type narrowing security leak

2021-12-29 Thread Rob Spoor
This isn't a security leak in Java (because that would mean it would be 
a security leak in any language that supports narrowing). This is a 
security leak in the application that does the narrowing. Developers 
should be aware that narrowing can change values. And furthermore, I 
don't think there are many developers that would perform this bounds 
check before the narrowing. Well, at least I wouldn't.


The fix you suggest could break many, many applications that use 
narrowing that actually *want* the value to be changed. An example is 
reading input streams byte-by-byte: the result is an int between 0 and 
255 (inclusive), or -1 for EOF. If the result is not -1, the result is 
almost always cast to a byte. The suggested fix would break for all 
values between 128 and 255 (inclusive) - half the available values.


I would rather have developers fix this in their code. There's already a 
method for "checked narrowing" from long to int: 
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Math.html#toIntExact(long).



Rob


On 29/12/2021 07:43, Fabrice Tiercelin wrote:

Greetings,
Any Java application may be concerned by a hacker attack using a type narrowing 
leak. If a program does the following things in this order:
  - Assert that a numerical id is allowed - Do a type narrowing among other 
things, even followed by a type widening - Do an action with the numerical id
...the hacker can do forbidden actions. Let's say that a given user doesn't 
have rights to change an amount for the id 63:
public void changeAmount(long userId, double newAmount) throws 
IllegalArgumentException {  isUserIdAllowedOrThrowException(userId); // userId 
= 4294967359

    int theUserId = (int) userId; // theUserId = 63    userId = theUserId; // 
userId = 63
   doChangeAmount(userId, newAmount); // userId = 63
}
It will fail passing 63 but it will success passing 4294967359 because 
4_294_967_359 is narrowed into 63. Let's call 4_294_967_359  a rebound of 63. 
4294967359 can be retrieved in few seconds by a basic program like this:
public class MyClass {
     public static void main(String args[]) {
   long targettedNumber = 63;
   
    for (long rebound = Integer.MAX_VALUE + 1; true; rebound++) {  int typeNarrowing = (int) rebound;

   long typeWidening = typeNarrowing;
   
   if (typeWidening == targettedNumber) {

   System.out.println("Rebound for " + targettedNumber + " found: " 
+ rebound);
   return;
   }
   }
     }
}
And it can be optimized. It works for any type narrowing. It not only works for 
numerical id but also for flags. If a numerical value should contain or not 
several flags, you can search a rebound among billions of rebounds until you 
find one with the perfect features. All the Java versions are concerned. The 
security layer can even be coded in another programming language.

To fix it, I suggest to add a test just before the type narrowing in the 
bytecode. The test verifies if the type narrowing will alter the numerical 
value. If true, it throws an unchecked exception or an error. Otherwise, it 
continues as currently. Note that it changes the behavior but the current 
behavior is dangerous, useless and is a failing case. You can add a compiler 
option to restore the original behavior but the new behavior should be the 
default.

Best regards,Fabrice TIERCELIN





Re: Adding an @Immutable annotation to Java

2021-11-26 Thread Rob Spoor
If this is really something that's desired, then why use an annotation 
when there's a keyword already available: const. However, there's a 
reason that's never been actually used in Java, and that's because it's 
so hard to get right.



On 26/11/2021 00:11, Alan Snyder wrote:

I like the idea of an @Immutable annotation. So much so, that I have created 
one and use it heavily.
However, my @Immutable is just for documentation; it does not have a rigorous 
semantics that would be
needed for a compiler to validate its use or generate different code.
But it could be used by lint-like tools to warn against suspicious code.

My @Immutable applies only to classes and interfaces, not variables or type 
parameters.
A class or interface is either @Immutable or it is not.
That avoids much complexity.

I think it is fine to have an @Immutable list (type) whose elements are mutable.
Is an instance of an immutable list with mutable elements immutable or not?
Tell me why you want to know and I might be able to answer the question.

I also think there are cases where an @Immutable type might have a mutable 
implementation
(in other words, it might have instance variables that are not final or have 
non-immutable types).
Examples include internal caching and configurability of performance or 
incidental behavior such as logging.

In general, immutability is in the mind of the beholder.

A case can be made that an interface or class that is @Immutable should only 
permit
extensions and implementing classes that are @Immutable.
Perhaps a compiler could validate that, but only at compilation time
(to ensure binary compatibility when an @Immutable annotation is added to an 
existing class or interface).

The idea of the compiler trying to enforce a semantics of immutability is scary.
Java tried to do this with uninitialized and final instance variables, and the 
result has been a disaster.
The rules make semantically valid code illegal, forcing complex workarounds.
(For example, suppose you want to compute a value, bind it to a final instance 
variable, and pass it to the superclass constructor.)
Yet it is still possible, actually quite easy, to write code that accesses 
uninitialized final variables.
I have code that checks a final @NotNull instance variable to ensure that it is 
not null.
IDEA tells me the check is unnecessary, but IDEA is wrong.

Immutability is a much more complicated concept than uninitialized.
Not something the compiler should mess with.

   Alan




On Nov 25, 2021, at 10:10 AM, Ralph Goers  wrote:

I would think that if a class is marked immutable that would imply all the 
fields in it and from its inherited
classes should be immutable. If fields are marked immutable then it would only 
apply to them.

What I wonder is what its relationship to final would be. The final annotation 
implies that a field must be
set in the constructor and cannot be modified after that. I would imagine that 
@immutable to have to imply
@final but would also apply at runtime. For example, where declaring a List 
field as final means you cannot
replace the List once it is set. I would expect @Immutable to do the same but 
also mean that you cannot
add elements to the List through that reference. But that would also mean that 
you cannot pass the reference
to another variable that isn’t also annotated with @Immutable - unless the 
immutable attribute becomes some
kind of internal flag on the object.

To be clear, this concept is always something I have wanted in Java. It is a 
real pain to have to do things like
List list = Collections.unmodifiableList(List.of(“foo”, “bar”));

Instead, it would be nice to be able to do
@Immutable List list = List.of(“foo”, “bar”);

Although the two could be implemented to do the same thing, the second could 
prevent passing the field in a
parameter that wasn’t declared @Immutable. Likewise, passing a non-immutable 
list in a parameter annotated
with @Immutable could cause the list to be copied to an immutable list 
automatically.

Ralph


On Nov 25, 2021, at 2:49 AM, Mariell Hoversholm  
wrote:

On Thu, 25 Nov 2021 at 10:03, Andrew Haley 
wrote:


Quick question, out of curiosity: how would it behave with respect to
inheritance? Can a @Immutable class inherit from an non immutable one?


And: does @Immutable mean deeply immutable? IMO it really should,
but that's harder to check, and we'd have to think about what this
means for binary compatibility.



As cited in the original email,

and the programmer could, for example, annotate a new record object with

@Immutable only if all its fields are annotated with @Immutable.

I would infer from this that it would mean deeply immutable.
To clarify further, the following record `Wrapper` would be legal only
because `A` has `@Immutable` on its _type_:

   @Immutable class A {}
   @Immutable record Wrapper(A a) {}

while this would not be legal:

   class A {}
   @Immutable record Wrapper(A a) {}

because `A` is not `@Immutable`. This could 

Feature request: custom default annotation attributes

2021-11-21 Thread Rob Spoor

Hi all,

I've been writing a few annotations lately that have one required 
attribute and some optional ones. That leaves me with three options:


1) Use value() for the required attribute. That becomes ugly when the 
optional attributes are given though.
2) Make developers write the attribute name every time. This is 
currently my choice.
3) Add the required attribute twice: once as value(), and once with a 
nice name. That adds complexity to annotation processing, and allows two 
different values for the same conceptual field.


I also know that I'm not the first one to encounter this issue. Spring 
is full of cases like this, and they've chosen the third option. For 
instance, RequestMapping.path[1] is an alias for value() (it's even 
annotated as such).


Now I was thinking: wouldn't it be nice to be able to define a custom 
default attribute? That could be done using an annotation, let's call it 
@DefaultAttribute. For this annotation the following rules would apply:
1) It can only be applied to annotation attributes. That means it gets 
special compiler support; that's also true for @Override though.
2) If value() is present, that is the default attribute automatically 
(like it is now).
3) It's a compiler error to have more than one default attribute, 
including value().


For users of the annotation, the same rules would apply as for value(): 
a single attribute value may be given without the name if there is a 
default attribute, either value() or an explicit one.


If we apply this to RequestMapping, the value() attribute could be 
dropped (in a new major version):


@interface RequestMapping {
@DefaultAttribute String[] path() default {};
// name, method, params, headers, consumes, produces as-is
}

Used: @RequestMapping("/test") // .path() now returns "/test"


Any thoughts?

Rob


[1] 
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html#path--


Re: TreeMap in JDK15 deviates from spec

2021-01-11 Thread Rob Spoor
This is a regression, because Java 11 shows "default" twice for the 
TreeMap, whereas Java 15 shows "null" twice.



On 11/01/2021 19:05, Phil Smith wrote:

Hello, I submitted bug report 9068554 recently, but I consider this a
pretty big issue and I'd like for this not to get lost in triage.

With JDK-8176894, a specialized implementation for computeIfAbsent was
added to TreeMap, however it doesn't handle null values correctly.
Spec states a mapping to null is equivalent to no mapping being
present, however code will `return t.value;` without checking that
value. The interface default, for reference, looks like `if ((v =
get(key)) == null)`.

A simple repro follows

TreeMap treemap = new TreeMap();
treemap.put("a", null);
System.out.println(treemap.computeIfAbsent("a", key -> "default"));
System.out.println(treemap.get("a"));

HashMap hashmap = new HashMap();
hashmap.put("a", null);
System.out.println(hashmap.computeIfAbsent("a", key -> "default"));
System.out.println(hashmap.get("a"));

Phil


Re: [BUG] InputStream.readNBytes doesn't correctly check for EOF

2020-12-21 Thread Rob Spoor

On 20/12/2020 19:15, Philippe Marschall wrote:



On 20.12.20 18:47, Rob Spoor wrote:

...

That "> 0" is incorrect here; it's allowed to return 0 before EOF


I don't think the method is allowed to return 0 before EOF. To quote
from the method Javadoc.

 > This method blocks until input data is available, end of file is
detected, or an exception is thrown.

 > If no byte is available because the stream is at end of file, the
value {@code -1} is returned; otherwise, at least one byte is read and
stored into {@code b}.

Cheers
Philippe


Hi Philippe,

You are right about the readNBytes method itself. I was talking about 
the read(byte[], int, int) method that is used internally by readNBytes. 
That method may return 0 before EOF, and if it does then readNBytes 
returns before it should.


[BUG] InputStream.readNBytes doesn't correctly check for EOF

2020-12-20 Thread Rob Spoor

According to the documentation of InputStream.readNBytes:

  Reads up to a specified number of bytes from the input stream. This
  method blocks until the requested number of bytes have been read, end
  of stream is detected, or an exception is thrown. This method does not
  close the input stream.

However, despite a comment, currently it may not necessarily read up to 
EOF. The problem is in a small result checking error:


// read to EOF which may read more or less than buffer size
while ((n = read(buf, nread,
Math.min(buf.length - nread, remaining))) > 0) {
nread += n;
remaining -= n;
}

That "> 0" is incorrect here; it's allowed to return 0 before EOF has 
been reached. It should be ">= 0", "> -1" or "!= -1", all of which 
correctly treat 0 and only break the loop once the read operation 
returns -1. Based on what's used in transferTo the best choice is 
probably ">= 0", to remain consistent in the same file.


Feature Request: CharSequence.getChars

2020-11-13 Thread Rob Spoor

Hi all,

In Java 9, compact strings were added. Ever since, I've been trying to 
use getChars instead of charAt for Strings. However, I prefer to also do 
the same for StringBuilder and StringBuffer. This can lead to some 
special cases. For instance, in Apache Commons I/O: 
https://github.com/apache/commons-io/blob/master/src/main/java/org/apache/commons/io/input/CharSequenceReader.java#L232


Is it perhaps not a good idea to add getChars as a default method to 
CharSequence? The implementation is simple enough:


default void getChars(int srcBegin, int srcEnd, char[] dst, int 
dstBegin) {

Objects.checkFromToIndex(srcBegin, srcEnd, length());
int n = srcEnd - srcBegin;
Objects.checkFromIndexSize(dstBegin, n, dst.length);
for (int i = srcBegin; i < srcEnd; i++) {
dst[dstBegin++] = charAt(i);
}
}

String, StringBuilder and StringBuffer automatically override it with 
their own methods, so these won't have to change at all.



I've already worked a bit on this, including more efficient overrides 
for CharBuffer and StringCharBuffer. The only other known 
implementation, Segment, won't profit much from a custom implementation, 
so I skipped it.


Should I continue with my work, or is it something that's considered not 
necessary? Adding it would allow a better implementation of 
Writer.append. For large CharSequences, that's currently hopelessly 
inefficient - first it converts the CharSequence to String, then to 
char[]. Instead, it could be implemented like write(String, int, int), 
with only one conversion (CharSequence to char[]).



Kind regards,

Rob


Re: Asking to contribute(?)

2020-11-13 Thread Rob Spoor

It appears this discussion has died out...

I really think it's a great addition to have a transform method added to 
not just Stream*, but also StringBuilder, StringBuffer and Optional. A 
search for classes containing "Builder" shows the following that could 
also be interesting:


* HttpClient.Builder, HttpRequest.Builder and WebSocket.Builder
* DateTimeFormatterBuilder
* ProcessBuilder


If we don't go for the Transformable interface (which I admit looks iffy 
due to the cast that can fail if a class decides to use a different 
generic type), I think we should at least add a transform method to 
Stream, StringBuilder, StringBuffer and Optional. The other classes I 
mentioned are probably not used as often as these 4, so let's omit them 
to keep the scope of the change limited.



* For the same reasons that OptionalInt, OptionalLong and OptionalDouble 
won't get (extra) map methods, let's skip IntStream, LongStream and 
DoubleStream as well.



On 05/11/2020 06:23, Justin Dekeyser wrote:

Hello,

Thank you for your answer, I appreciate!

Indeed, it is clear to me that if the feature should be a concern of both
String and Stream (or more?), a common contract can be designed.

The impl. you sketch is the more natural one I think. (it's also the one I
gave in the other mailing grap about that toList stuff, so I guess it's ok!)

I am just a bit cold about the idea that the spec will make the compiler's
job, but I guess in Java there is no work around.

I don't know what the community thinks about it.

Regards,

Justin Dekeyser

On Wednesday, November 4, 2020, Rob Spoor  wrote:


On 04/11/2020 14:18, Justin Dekeyser wrote:


Hello everyone,

I have been following this mailing list for several months, and
earlier today my attention was drawn to
https://bugs.openjdk.java.net/browse/JDK-8140283. Actually I've been
dreaming of such a feature for a long time now.

I would really be interested in solving it, but I do not know its
current state nor if someone would agree to sponsor my work on that.

It would be my very first intervention in the Java code base.
(Still have to make sure the Oracle agreement paper does not conflict
with my current job contract, so nothing's ready for now.)

Thank you for your time,

Best regards,

Justin Dekeyser



I'd like this feature as well, but why stop at Stream? String already has
the transform method, but StringBuilder (and StringBuffer) could also use
it.

And that's where you're likely to start copy pasting. I've done so for
several builder classes I've written for myself. So here's a thought: why
add this method to classes, when you can create a trait using an interface
with a default method?

 public interface Transformable {

 default  R transform(Function f) {
 // note: this would need documentation that a class X is
 // only allowed to implement Transformable
 return f.apply((T) this);
 }
 }

So you could get the following, and each would automatically get the
transform method:
* public class String implements Transformable
* public class StringBuilder implements Transformable
* public class StringBuffer implements Transformable
* public interface Stream implements Transformable>


Re: Asking to contribute(?)

2020-11-04 Thread Rob Spoor

On 04/11/2020 14:18, Justin Dekeyser wrote:

Hello everyone,

I have been following this mailing list for several months, and
earlier today my attention was drawn to
https://bugs.openjdk.java.net/browse/JDK-8140283. Actually I've been
dreaming of such a feature for a long time now.

I would really be interested in solving it, but I do not know its
current state nor if someone would agree to sponsor my work on that.

It would be my very first intervention in the Java code base.
(Still have to make sure the Oracle agreement paper does not conflict
with my current job contract, so nothing's ready for now.)

Thank you for your time,

Best regards,

Justin Dekeyser



I'd like this feature as well, but why stop at Stream? String already 
has the transform method, but StringBuilder (and StringBuffer) could 
also use it.


And that's where you're likely to start copy pasting. I've done so for 
several builder classes I've written for myself. So here's a thought: 
why add this method to classes, when you can create a trait using an 
interface with a default method?


public interface Transformable {

default  R transform(Function f) {
// note: this would need documentation that a class X is
// only allowed to implement Transformable
return f.apply((T) this);
}
}

So you could get the following, and each would automatically get the 
transform method:

* public class String implements Transformable
* public class StringBuilder implements Transformable
* public class StringBuffer implements Transformable
* public interface Stream implements Transformable>


Re: [BUG] Java 15: DecimalFormatSymbols overrides equals but not hashCode

2020-09-15 Thread Rob Spoor

On 15/09/2020 22:02, Pavel Rappo wrote:

On 15 Sep 2020, at 20:50, Brian Burkhalter  wrote:


On Sep 15, 2020, at 12:38 PM, Kevin Rushforth  
wrote:

I see this in DecimalFormatSymbols:


 /**
  * Override hashCode.
  */

   private volatile int hashCode;

 @Override
 public int hashCode() {

Although, I'm not sure why the intervening private field would prevent javadoc 
from generating at least a method with an empty doc


https://bugs.openjdk.java.net/browse/JDK-8187386



So in this case, the solution would be to remove the superfluous 
"Override equals." comment from the equals method, right?




Re: [BUG] Java 15: DecimalFormatSymbols overrides equals but not hashCode

2020-09-15 Thread Rob Spoor
Hmm, I could have sworn I checked 
https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/text/DecimalFormatSymbols.java 
and didn't find it...


I guess it's a false positive then.


On 15/09/2020 21:36, Brian Burkhalter wrote:

Hello,

The override of hashCode() looks like it is still there in JDK 15 [1]. I don’t 
know however why it does not appear as such in the javadoc [2].

Brian

[1] 
http://hg.openjdk.java.net/jdk/jdk15/file/fb7064dc63f9/src/java.base/share/classes/java/text/DecimalFormatSymbols.java#l760
[2] 
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/text/DecimalFormatSymbols.html


On Sep 15, 2020, at 12:14 PM, Rob Spoor  wrote:

In Java 14 and before, DecimalFormatSymbols had overrides for both equals and 
hashCode. In Java 15, the override for hashCode has disappeared, and it now 
inherits hashCode from java.lang.Object. That means it now violates the 
contract for equals + hashCode: two equal DecimalFormatSymbols instances can 
have different hash codes.


[BUG] Java 15: DecimalFormatSymbols overrides equals but not hashCode

2020-09-15 Thread Rob Spoor
In Java 14 and before, DecimalFormatSymbols had overrides for both 
equals and hashCode. In Java 15, the override for hashCode has 
disappeared, and it now inherits hashCode from java.lang.Object. That 
means it now violates the contract for equals + hashCode: two equal 
DecimalFormatSymbols instances can have different hash codes.


Re: Feature Request

2020-07-21 Thread Rob Spoor
If you need something right now, you can try 
https://commons.apache.org/proper/commons-text/javadocs/api-release/org/apache/commons/text/StringSubstitutor.html.



On 21/07/2020 09:29, Jessica wrote:

Hi,

I would like to strongly request Java have the ability to do string
interpolation.
It is such a great convenience and allows for faster, more efficient coding
that is easier to read.

Is this feature on the roadmap in the foreseeable future?

Thank you!

Jessica Risavi


Virus-free.
www.avg.com

<#DAB4FAD8-2DD7-40BB-A1B8-4E2AA1F9FDF2>


Re: [PATCH] 8245694 : java.util.Properties.entrySet() does not override java.lang.Object methods

2020-05-30 Thread Rob Spoor
There's still a little regression there since Java 8, if you add the 
keySet(), values() or entrySet() to the Properties object as either key 
or value; in Java 8 this would cause "(this Collection)" to be included, 
while even with this fix that would cause a StackOverflowError. However, 
given that it's only a corner case for most Collections and Maps in the 
first place, and with Properties objects even more so, I don't think 
anyone would mind this regression.


Rob

On 30/05/2020 20:31, Lisa Li wrote:

Hi,

Please help review the fix for JDK-8245694
.  And this is my very
first patch submission. I know it's not perfect.



*BUG DESCRIPTION*:

JDK-8245694  :
java.util.Properties.entrySet()
does not override java.lang.Object methods since java 9.


*PROPOSED FIX*:

Add delegating overrides for equals(), hashCode(), and toString().


*PATCH*:

# HG changeset patch
# User yuli
# Date 1590841711 -28800
#  Sat May 30 20:28:31 2020 +0800
# Node ID 7dc946e5b5863291fa070bfdbdce48aefbe87b7b
# Parent  8e28aae5068069e853673148e4d3f44cb50350a7
8245694: java.util.Properties.entrySet() does not override Object methods
Summary: Add missing override methods
Contributed-by: Yu Li 

diff --git a/src/java.base/share/classes/java/util/Properties.java
b/src/java.base/share/classes/java/util/Properties.java
--- a/src/java.base/share/classes/java/util/Properties.java
+++ b/src/java.base/share/classes/java/util/Properties.java
@@ -1414,6 +1414,21 @@
  return entrySet.retainAll(c);
  }

+ @Override
+public boolean equals(Object o) {
+return entrySet.equals(o);
+}
+
+@Override
+public int hashCode() {
+return entrySet.hashCode();
+}
+
+@Override
+public String toString() {
+return entrySet.toString();
+}
+
  @Override
  public Iterator> iterator() {
  return entrySet.iterator();
diff --git a/test/jdk/java/util/Properties/PropertiesEntrySetTest.java
b/test/jdk/java/util/Properties/PropertiesEntrySetTest.java
new file mode 100644
--- /dev/null
+++ b/test/jdk/java/util/Properties/PropertiesEntrySetTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights
reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary tests the entrySet() method of Properties class
+ * @author  Yu Li
+ * @bug 8245694
+ */
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+public class PropertiesEntrySetTest {
+
+public static void main(String[] args) {
+
+testEntrySet();
+
+}
+
+private static void assertTrue(boolean value) {
+if (!value) {
+throw new RuntimeException("Failure in Properties testing.");
+}
+}
+
+private static void assertFalse(boolean value) {
+if (value) {
+throw new RuntimeException("Failure in Properties testing.");
+}
+}
+
+private static void testEntrySet() {
+Properties a = new Properties();
+Set> aEntrySet = a.entrySet();
+assertFalse(aEntrySet.equals(null));
+assertTrue(aEntrySet.equals(aEntrySet));
+
+Properties b = new Properties();
+Set> bEntrySet = b.entrySet();
+assertTrue(aEntrySet.equals(bEntrySet));
+assertTrue(aEntrySet.hashCode() == bEntrySet.hashCode());
+
+a.setProperty("p1", "1");
+assertFalse(aEntrySet.equals(bEntrySet));
+assertFalse(bEntrySet.equals(aEntrySet));
+assertFalse(aEntrySet.hashCode() == bEntrySet.hashCode());
+
+b.setProperty("p1", "1");
+assertTrue(aEntrySet.equals(bEntrySet));
+assertTrue(aEntrySet.hashCode() == bEntrySet.hashCode());
+
+Properties c = new Properties();
+c.setProperty("p1", "2");
+Set> cEntrySet = c.entrySet();
+

Re: [BUG] java.util.Properties.entrySet() does not override java.lang.Object methods since Java 9

2020-05-23 Thread Rob Spoor

On 23/05/2020 21:13, Rob Spoor wrote:

Hi,

I was working on upgrading a library of mine from Java 8 to 11, and I 
noticed my unit tests started failing. Some investigation showed that in 
Java 9, java.util.Properties was rewritten to no longer rely on the fact 
that it extends Hashtable. One of the changes was to use a private 
static class called EntrySet. However, while this class implements most 
methods from java.util.Set, it's actually missing two: equals and 
hashCode. As a result it does not adhere to the general contract of 
java.util.Set. It's also missing a toString implementation, thereby 
inheriting its String representation from java.lang.Object. I've checked 
the source code up to Java 14, and even the Mercurial repository, and 
this issue still exists.


I think this could be solved as simply as by having this private 
EntrySet class extend AbstractSet, or otherwise delegate its methods to 
its entrySet field. The latter is probably preferred, as it matches the 
implementation of the same methods of the java.util.Properties class 
itself.


Rob


I've also noticed that keySet() and values() may behave differently if 
you add an entry with the keySet() as key or values() as value. While 
before that would have printed "(this Collection)", it will now cause a 
StackOverflowError because the key set or values collection no longer 
contains itself (which is the keySet() or values() from the backing 
ConcurrentHashMap), but a synchronized wrapper. While this is a rare 
corner case (nobody in their right mind would add anything but Strings 
to a java.util.Properties object), it is probably an unintended side 
effect of the rewrite of java.util.Properties.


[BUG] java.util.Properties.entrySet() does not override java.lang.Object methods since Java 9

2020-05-23 Thread Rob Spoor

Hi,

I was working on upgrading a library of mine from Java 8 to 11, and I 
noticed my unit tests started failing. Some investigation showed that in 
Java 9, java.util.Properties was rewritten to no longer rely on the fact 
that it extends Hashtable. One of the changes was to use a private 
static class called EntrySet. However, while this class implements most 
methods from java.util.Set, it's actually missing two: equals and 
hashCode. As a result it does not adhere to the general contract of 
java.util.Set. It's also missing a toString implementation, thereby 
inheriting its String representation from java.lang.Object. I've checked 
the source code up to Java 14, and even the Mercurial repository, and 
this issue still exists.


I think this could be solved as simply as by having this private 
EntrySet class extend AbstractSet, or otherwise delegate its methods to 
its entrySet field. The latter is probably preferred, as it matches the 
implementation of the same methods of the java.util.Properties class itself.


Rob


Re: Question about String.toUpperCase behaviour

2019-10-29 Thread Rob Spoor

On 28/10/2019 21:34, Florian Weimer wrote:

* Сергей Цыпанов:


Hello,

current implementation of e.g. String.toUpperCase() returns the object
it was called on in case all code points are in upper case.

E.g. this test

@Test
public void upperCase() {
   String str = "AZ";// English
   assert str == str.toUpperCase();
   
   str = "АЯ";   // Russian

   assert str == str.toUpperCase();
}

passes for both Latin-1 and UTF-16. This assumption allows to simplify this:

boolean isUpperCase = str.toUpperCase().equals(str);

to

boolean isUpperCase = str.toUpperCase() == str;

Could this transformation be legal assuming that existing behaviour of
String.toUpperCase is not documented?


Valid for whom?  For the JDK itself, sure.  But programmers really
should not assume such undocumented behavior when writing Java
programs, and neither shoud external tools targeting the JVM.



I agree. There is no reason to use == instead of equals. Not for 
readability, because it will most likely confuse people who will come 
asking why you're not using equals. Not for performance, because since 
at least Java 7 String.equals starts with this:


if (this == anObject) {
return true;
}

So in other words: keep using equals, it's the cleaner option.


RFE: annotation for resource wrapper methods

2019-08-10 Thread Rob Spoor

Hi,

When you wrap a resource (InputStream, etc) using a class constructor 
(e.g. new BufferedInputStream(...)), compilers usually don't complain. 
If you do the exact same thing using a utility method, compilers aren't 
that smart anymore. For instance, the following produces a warning that 
the FileInputStream may not be closed, even though the wrap method 
returns a new InputStream that closes the FileInputStream if it's closed 
itself:


try (InputStream decoded = Base64.getDecoder().wrap(new 
FileInputStream("filename"))) {

...
}

It would be nice if there were some annotation that we could use to mark 
a method as being resource-safe, because they either close the resource, 
or return a wrapper around it. It would be a bit like @SafeVarargs but 
for resources. Methods like wrap would then be annotated with this new 
annotation, and compilers shouldn't complain anymore. The alternative is 
a lot more verbose:


try (@SuppressWarnings("resource") InputStream decoded = 
Base64.getDecoder().wrap(new FileInputStream(""))) {


}


(I don't know if this is the right mailing list, but I couldn't find a 
better one.)



Kind regards,

Rob


[BUG] Inet6Address.isIPv4CompatibleAddress uses wrong prefix

2019-06-24 Thread Rob Spoor
I found a bug in Inet6Adress.isIPv4CompatibleAddress(). While parsing 
correctly uses the ::: format, isIPv4CompatibleAddress() 
checks for :: instead. An example:


Inet6Address address = (Inet6Address) 
InetAddress.getByName("::192.168.1.13");
System.out.printf("%s: %b%n", address, 
address.isIPv4CompatibleAddress());


This should print false, but instead it prints true.

The error is in the Inet6Address.Inet6AddressHolder class:

boolean isIPv4CompatibleAddress() {
if ((ipaddress[0] == 0x00) && (ipaddress[1] == 0x00) &&
(ipaddress[2] == 0x00) && (ipaddress[3] == 0x00) &&
(ipaddress[4] == 0x00) && (ipaddress[5] == 0x00) &&
(ipaddress[6] == 0x00) && (ipaddress[7] == 0x00) &&
(ipaddress[8] == 0x00) && (ipaddress[9] == 0x00) &&
(ipaddress[10] == 0x00) && (ipaddress[11] == 0x00))  {
return true;
}
return false;
}

I think that bytes 10 and 11 should both be (byte) 0xFF instead of 0x00. 
This is what's being used in IPAddressUtil, which is used for parsing:


private static boolean isIPv4MappedAddress(byte[] addr) {
if (addr.length < INADDR16SZ) {
return false;
}
if ((addr[0] == 0x00) && (addr[1] == 0x00) &&
(addr[2] == 0x00) && (addr[3] == 0x00) &&
(addr[4] == 0x00) && (addr[5] == 0x00) &&
(addr[6] == 0x00) && (addr[7] == 0x00) &&
(addr[8] == 0x00) && (addr[9] == 0x00) &&
(addr[10] == (byte)0xff) &&
(addr[11] == (byte)0xff))  {
return true;
}
return false;
}

Maybe it's an idea to let Inet6Address.Inet6AddressHolder delegate to 
this latter method?



Rob


Re: java.util.regex.Matcher and StringBuilder/StringBuffer APIs

2019-06-21 Thread Rob Spoor

Maybe because Appendable comes with IOExceptions?


On 21/06/2019 17:06, Robert Marcano wrote:
Greetings. Is there a reason the newest APIs added to Matcher 
(performance maybe?) with StringBuilder arguments weren't added as 
Appendable instead?


For example:

   public StringBuilder appendTail(StringBuilder sb)
   public Matcher appendReplacement(StringBuilder sb, String replacement)

Could have been:

   public  T appendTail(T ap)
   public Matcher appendReplacement(Appendable ap, String replacement)

Both appendReplacement(...) implementations are copies, that could be 
reduced to a simple one if Appendable was the argument, and the present 
ones calling to that.


If this sounds reasonable, I could write a patch for testing.

Note: I was hit with this when trying to use another kind of Appendable 
optimized for my use case.




Re: Proposal to enhance Stream.collect

2019-02-24 Thread Rob Spoor
If you already know the size and are not going to parallelize your 
stream, you can simply use Collectors.toCollection:


Stream.of(1,2,3)
  .map(i -> i+1)
  .collect(Collectors.toCollection(() -> new ArrayList<>(3)));

It could perhaps be a bit easier if Collectors.toList would be 
overloaded to accept the initial size, but that would restrict the 
method to always use ArrayList (or another List with a predefined capacity).



On 23/02/2019 23:27, August Nagro wrote:

Calling Stream.collect(Collector) is a popular terminal stream operation.
But because the collect methods provide no detail of the stream's
characteristics, collectors are not as efficient as they could be.

For example, consider a non-parallel, sized stream that is to be collected
as a List. This is a very common case for streams with a Collection source.
Because of the stream characteristics, the Collector.supplier() could
initialize a list with initial size (since the merging function will never
be called), but the current implementation prevents this.

I should note that the characteristics important to collectors are those
defined by Spliterator, like: Spliterator::characteristics,
Spliterator::estimateSize, and Spliterator::getExactSizeIfKnown.

One way this enhancement could be implemented is by adding a method
Stream.collect(Function collectorBuilder).
ReadOnlySpliterator would implement the spliterator methods mentioned
above, and Spliterator would be made to implement this interface.

For example, here is a gist with what Collectors.toList could look like:
https://gist.github.com/AugustNagro/e66a0ddf7d47b4f11fec8760281bb538

ReadOnlySpliterator may need to be replaced with some stream specific
abstraction, however, since Stream.spliterator() does not return with the
correct characteristics. The below code returns false, for example (is this
a bug?):

Stream.of(1,2,3).parallel().map(i ->
i+1).spliterator().hasCharacteristics(Spliterator.CONCURRENT)

Looking forward to your thoughts,

- August Nagro


Re: RFE: add missing methods to Optional, OptionalInt, OptionalLong and OptionalDouble

2019-02-20 Thread Rob Spoor
I was actually missing at least one of the map methods. I have a method 
that is returning an OptionalInt, and I wanted to easily turn that into 
an Optional by applying mapToObj(Integer::valueOf). The same 
could also be done for OptionalLong -> Optional and OptionalDouble 
-> Optional.


However, Valhalla's Optional will indeed make OptionalInt more or 
less superfluous (likewise for Optional and Optional). 
That raises one question - would it be worth adding these "missing" 
methods for just a few releases, after which they would no longer be 
necessary? They would not differ from the base type any more than 
IntStream, LongStream and DoubleStream differ from Stream, so that 
shouldn't block it.



Speaking of the OptionalInt returning method, that is a version of 
Integer.parseInt that does not throw an exception but instead returns an 
OptionalInt (to prevent having the exception created and caught, only to 
be ignored). In line with C# I was calling it tryParseInt. I was 
actually intending to have an RFE for that one too, but in light of the 
upcoming Optional I think it's probably a better idea to wait with 
that until it's possible to return an Optional. Otherwise this 
method would be stuck with the "old" OptionalInt return type.



On 19/02/2019 17:01, Brian Goetz wrote:
This is a very nice patch, complete with spec and tests, and evidence of 
OCA.


But, before we talk about patches and code, let's step back and talk 
about stewardship.  With API proposals, we like to start with problems, 
rather than solutions: what problems we are concerned with, and are 
these are problems that need to be solved in the JDK?  Assuming we like 
the answers to the former, we can then move on to whether the proposed 
solution is the right one, and then to details like spec and code review.


We are currently trying to avoid adding anything to 
OptionalInt/Long/Double, because our current plan is to replace these 
with a specialized Optional once Valhalla delivers.  Any methods 
that differ from the base type (Optional) creates potential roadblocks 
to such a migration, so we'd prefer to leaves these classes be.


To the main question, though, whether Optional should have specialized 
map and flatMap methods ... I'm skeptical.  The goal was never to create 
parity between Optional and Stream, and my gut reaction is that the 
return on additional API surface area here is negative.  But, we can 
surely have a discussion on this.




On 2/16/2019 7:52 AM, Rob Spoor wrote:
I noticed that, while Stream and its primitive equivalents have 
multiple map and flapMap methods, Optional and its primitive 
equivalents were missing those. Since these can still be very useful, 
I wrote a patch to add the following methods:


* Optional: mapToInt, mapToLong, mapToDouble, flatMapToInt, 
flatMapToLong, flatMapToDouble

* OptionalInt: map, mapToObj, mapToLong, mapToDouble, flatMap
* OptionalLong: map, mapToObj, mapToInt, mapToDouble, flatMap
* OptionalDouble: map, mapToObj, mapToInt, mapToLong, flatMap

I did not add any more flatMap methods to OptionalInt, OptionalLong 
and OptionalDouble because these also don't exist on IntStream, 
LongStream and DoubleStream.



In addition, I also added the missing or method to OptionalInt, 
OptionalLong and OptionalDouble based on that of Optional.



My OCA has been processed on 2019-01-22.


Rob


RFE: add missing methods to Optional, OptionalInt, OptionalLong and OptionalDouble

2019-02-16 Thread Rob Spoor
I noticed that, while Stream and its primitive equivalents have multiple 
map and flapMap methods, Optional and its primitive equivalents were 
missing those. Since these can still be very useful, I wrote a patch to 
add the following methods:


* Optional: mapToInt, mapToLong, mapToDouble, flatMapToInt, 
flatMapToLong, flatMapToDouble

* OptionalInt: map, mapToObj, mapToLong, mapToDouble, flatMap
* OptionalLong: map, mapToObj, mapToInt, mapToDouble, flatMap
* OptionalDouble: map, mapToObj, mapToInt, mapToLong, flatMap

I did not add any more flatMap methods to OptionalInt, OptionalLong and 
OptionalDouble because these also don't exist on IntStream, LongStream 
and DoubleStream.



In addition, I also added the missing or method to OptionalInt, 
OptionalLong and OptionalDouble based on that of Optional.



My OCA has been processed on 2019-01-22.


Rob
diff --git a/src/java.base/share/classes/java/util/Optional.java 
b/src/java.base/share/classes/java/util/Optional.java
--- a/src/java.base/share/classes/java/util/Optional.java
+++ b/src/java.base/share/classes/java/util/Optional.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,9 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
+import java.util.function.ToDoubleFunction;
+import java.util.function.ToIntFunction;
+import java.util.function.ToLongFunction;
 import java.util.stream.Stream;
 
 /**
@@ -267,6 +270,69 @@
 }
 
 /**
+ * If a value is present, returns an {@code OptionalInt} describing the
+ * result of applying the given mapping function to the value, otherwise
+ * returns an empty {@code OptionalInt}.
+ *
+ * @param mapper the mapping function to apply to a value, if present
+ * @return an {@code OptionalInt} describing the result of applying a
+ * mapping function to the value of this {@code Optional}, if a
+ * value is present, otherwise an empty {@code Optional}
+ * @throws NullPointerException if the mapping function is {@code null}
+ * @since 13
+ */
+public OptionalInt mapToInt(ToIntFunction mapper) {
+Objects.requireNonNull(mapper);
+if (!isPresent()) {
+return OptionalInt.empty();
+} else {
+return OptionalInt.of(mapper.applyAsInt(value));
+}
+}
+
+/**
+ * If a value is present, returns an {@code OptionalLong} describing the
+ * result of applying the given mapping function to the value, otherwise
+ * returns an empty {@code OptionalLong}.
+ *
+ * @param mapper the mapping function to apply to a value, if present
+ * @return an {@code OptionalLong} describing the result of applying a
+ * mapping function to the value of this {@code Optional}, if a
+ * value is present, otherwise an empty {@code Optional}
+ * @throws NullPointerException if the mapping function is {@code null}
+ * @since 13
+ */
+public OptionalLong mapToLong(ToLongFunction mapper) {
+Objects.requireNonNull(mapper);
+if (!isPresent()) {
+return OptionalLong.empty();
+} else {
+return OptionalLong.of(mapper.applyAsLong(value));
+}
+}
+
+/**
+ * If a value is present, returns an {@code OptionalDouble} describing the
+ * result of applying the given mapping function to the value, otherwise
+ * returns an empty {@code OptionalDouble}.
+ *
+ * @param mapper the mapping function to apply to a value, if present
+ * @return an {@code OptionalDouble} describing the result of applying a
+ * mapping function to the value of this {@code Optional}, if a
+ * value is present, otherwise an empty {@code Optional}
+ * @throws NullPointerException if the mapping function is {@code null}
+ * @since 13
+ */
+public OptionalDouble mapToDouble(ToDoubleFunction mapper) {
+Objects.requireNonNull(mapper);
+if (!isPresent()) {
+return OptionalDouble.empty();
+} else {
+return OptionalDouble.of(mapper.applyAsDouble(value));
+}
+}
+
+/**
  * If a value is present, returns the result of applying the given
  * {@code Optional}-bearing mapping function to the value, otherwise 
returns
  * an empty {@code Optional}.
@@ -297,6 +363,90 @@
 }
 
 /**
+ * If a value is present, returns the result of applying the given
+ * {@code OptionalInt}-bearing mapping function to the value, otherwise
+ * returns an empty {@code OptionalInt}.
+ *
+ * This method is similar to {@link #mapToInt(ToIntFunction)}, but the
+ * mapping function is 

Re: 8212620: Provide a mechansim to allow a class/method to request filtering from the stack trace

2019-01-11 Thread Rob Spoor

On 10/01/2019 22:59, Mandy Chung wrote:



On 1/10/19 11:30 AM, Rob Spoor wrote:

I had an idea that can possibly help solve three issues:
* 8212620
Provide a mechansim to allow a class/method to request filtering from 
the stack trace


This RFE is not just about stack trace format and a generic stack trace 
printer has no knowledge if a stack frame is implementation-specific. A 
library developer may want certain classes or methods to hide from the 
user (eliminating the implementation details) and remove noise from the 
stack trace.


One idea is some kind of annotation that a library developer can tag the 
methods to be hidden from stack trace by default.


So this proposal does not address the use case of 8212620.


I may have RFE 8212620 differently. My proposal would also allow stack 
trace elements to be filtered out of stack traces, by providing a 
filtering StackTracePrinter. This would be initiated from the caller (or 
system if the default is replaced). I now see that 8212620 is about 
letting the called method or class itself determine that it should show 
up in stack traces. Both solutions could give the same end result, and 
could probably even be mixed.





* 8211152
Improve unclear and incomplete Exception stack trace
* 6507809
"Caused by" notation for stack traces unnecessarily hard to read




I didn't spend time on this.  The only thing I would say about these 2 
RFEs is that they both propose to change the current stack trace format 
that will likely break tools parsing the output.   Keeping the default 
format unmodified and allowing to plugin a custom formatter is one 
option to consider.


Mandy

The issue described in all three is that the way stack traces are 
printed is different from what people want. One solution could be to 
pull the formatting logic away from Throwable. This can be done by 
introducing an interface similar to Thread.UncaughtExceptionHandler. 
For instance:


    public interface StackTracePrinter {
    void printStackTrace(Throwable t, PrintStream out);
    void printStackTrace(Throwable t, PrintWriter out);
    }

Throwable could get a static defaultStackTracePrinter field like 
Thread.defaultUncaughtExceptionHandler, and Throwable's 
printStackTrace methods would delegate to this default.


There can then be implementation DefaultStackTracePrinter that uses 
the current format, and different implementations for the three 
issues. (Small implementation improvement: instead of using 
PrintStreamOrWriter, WrappedPrintStream and WrappedPrintWriter, the 
private printStackTrace method could take a lock and a 
Consumer as arguments. This would then be called as 
"printStackTrace(s, s::println)".)



Unfortunately, getOurStackTrace() will not be available to all 
implementations, so to prevent having to call getStackTrace() 
Throwable should get another method List 
getStackTraceList() that returns List.of(getOurStackTrace()) (possibly 
cached), or otherwise 
Collections.unmodifiableList(Arrays.asList(getOurStackTrace())).



There is one thing that I haven't been able to figure out though, and 
that's specifying different StackTracePrinters for different 
applications in application containers etc. Maybe someone can think of 
a good mechanism to support this.


8212620: Provide a mechansim to allow a class/method to request filtering from the stack trace

2019-01-10 Thread Rob Spoor

I had an idea that can possibly help solve three issues:
* 8212620
Provide a mechansim to allow a class/method to request filtering from 
the stack trace

* 8211152
Improve unclear and incomplete Exception stack trace
* 6507809
"Caused by" notation for stack traces unnecessarily hard to read


The issue described in all three is that the way stack traces are 
printed is different from what people want. One solution could be to 
pull the formatting logic away from Throwable. This can be done by 
introducing an interface similar to Thread.UncaughtExceptionHandler. For 
instance:


public interface StackTracePrinter {
void printStackTrace(Throwable t, PrintStream out);
void printStackTrace(Throwable t, PrintWriter out);
}

Throwable could get a static defaultStackTracePrinter field like 
Thread.defaultUncaughtExceptionHandler, and Throwable's printStackTrace 
methods would delegate to this default.


There can then be implementation DefaultStackTracePrinter that uses the 
current format, and different implementations for the three issues. 
(Small implementation improvement: instead of using PrintStreamOrWriter, 
WrappedPrintStream and WrappedPrintWriter, the private printStackTrace 
method could take a lock and a Consumer as arguments. This would 
then be called as "printStackTrace(s, s::println)".)



Unfortunately, getOurStackTrace() will not be available to all 
implementations, so to prevent having to call getStackTrace() Throwable 
should get another method List getStackTraceList() 
that returns List.of(getOurStackTrace()) (possibly cached), or otherwise 
Collections.unmodifiableList(Arrays.asList(getOurStackTrace())).



There is one thing that I haven't been able to figure out though, and 
that's specifying different StackTracePrinters for different 
applications in application containers etc. Maybe someone can think of a 
good mechanism to support this.




Feature suggestion: Add support to Base64.Encoder and Base64.Decoder to wrap Writer / Reader

2019-01-08 Thread Rob Spoor
Java 8 added Base64 with its nested classes Encoder and Decoder. These 
both have methods to wrap an OutputStream / InputStream respectively. 
However, base64 is text; the alphabets exist out of ASCII characters 
only. This is (somewhat) acknowledged by the presence of the 
encodeToString(byte[]) and decode(String) methods. Doesn't it then also 
make sense to add methods to wrap a Writer and Reader respectively? 
(Perhaps Appendable / Readable is even better to provide more 
flexibility.) When reading an exception can be thrown if an unsupported 
character is encountered.


I have already written a simple example to wrap a StringBuilder in an 
OutputStream that I then wrap using Base64.Encoder: 
https://github.com/robtimus/data-url/blob/master/src/main/java/com/github/robtimus/net/protocol/data/DataURLs.java. 
This could probably add some validation that characters are limited to 
the actual alphabet in the convert method, but I was a bit lazy there.


If an Appendable is wrapped the flush and close methods should delegate 
to the wrapped object if that implements Flushable / Closeable respectively.