UUID.fromString(var) is accepting additional characters in Java - java

I have a requirement where I accept a UUID and check whether the UUID is in valid format or not. Package java.util provides a UUID.FromString(var) method which accepts a variable and it throws an exception when it is not in valid format.
For some unknown reasons, it's accepting an additional character and filters it out instead of throwing an exception.
For example,
String var1="BAAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA"
UUID.fromString(var1)
Here, there is an additional character B but instead of throwing an exception, it's filtering it out as "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA".
Can anyone help me understand why is this happening?
I am using Java 8.

Historically, it looks like Java's UUID class has been very lenient in what it accepts. This includes too short segments, and too long segments. This behaviour was tightened up somewhat between Java 8 and Java 11 (I didn't want to check Java 9 or 10 to see exactly when), as Java 11 no longer accepts your example (but still accepts too short segments).
I haven't been able to identify the exact bug in the Java bug database that changed this, but there are a lot around this behaviour (example: JDK-8216407 : java.util.UUID.fromString accepts input that does not match expected format), but most of them are either still open, closed as duplicate, or marked as "won't fix" because of backwards compatibility concerns.

I double-checked (javac 11.0.15)
and it is behaving as expected.
Here is an example of how I tested it:
I guess that you are not handling the exception properly.
class Example {
public static void main(String[] args) {
// Valid case
System.out.println(isValidUUID("AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA"));
// Invalid cases
System.out.println(isValidUUID("Cc21a392e-3da6-4cd4-ac9f-9d963b313e22"));
System.out.println(isValidUUID("BAAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA"));
System.out.println(isValidUUID("AAAA-AAAAAAAAAAAA"));
System.out.println(isValidUUID("Hope this helps"));
}
/**
Check if a supplied UUID is valid
*/
public static boolean isValidUUID(String uuid) {
try {
UUID.fromString(uuid);
} catch (RuntimeException e) {
return false;
}
return true;
}
}

Related

How to define ParameterType with code-dependent RegEx in Cucumber without TypeRegistry?

In Cucumber 7.4.1+ TypeRegistry is deprecated in favour of annotations.
Indeed, as of today, I have never used anything but #ParameterType to define my ParameterTypes. Searching for alternatives, TypeRegistry is the only one I have found - but if it is "on the way out", of course I'd rather not start using it now.
Given a construct like this I cannot use annotations because those cannot take static parameters:
enum SpecialDate implements Supplier<Date> {
TODAY { #Override public Date get() { return Date(); } },
// YESTERDAY, etc.
;
static String typeSafeRegEx() {
return Arrays.stream(Zeitpunkt.values())
.map(SpecialDate::specName)
.collect(Collectors.joining("|"));
}
static SpecialDate from(final String specName) {
return valueOf(StringUtils.upperCase(specName));
}
String specName() {
return StringUtils.capitalize(StringUtils.lowerCase(this.name()));
}
}
public class ParameterTypes {
// does not compile: "Attribute value must be constant"
#ParameterType("(" + SpecialDate.typeSafeRegEx() + ")")
public Date specialDate(final String specName) {
return SpecialDate.from(specName).get();
}
}
A so-specified regEx is nice, because it will only match values guaranteed to be mappable, so I need no additional error handling code beyond Cucumber's own. The list of allowed values is also maintenance-free (compared to a "classic" switch which would silently grow incorrect when adding new values).
The alternative would be to use an unsafe switch + default: throw, strictly worse because it has to be maintained manually.
(Or, I guess, to just valueOf whatever + wrap into a more specific exception, when it eventually fails.)
To me, Cucumber's native UndefinedStepException appears to be the best outcome on a mismatch, because everyone familiar with Cucumber will immediately recognise it, unlike a project-specific one.
I see that e.g. the ParameterType class is not deprecated but cannot seem to find information how to use it without TypeRegistry.
FWIW:
Updating the libraries or Java would not be an issue. (But downgrading is sadly not viable.)
Business Specialists want to write examples like [Today], [Today + 1], [Yesterday - 3], etc. If this can be realised more elegantly using a different approach, X/Y answers would also be welcome.
An example step looks like this:
And I enter into the field 'Start of Implementation' the <begin>
Examples:
| begin
| [Today]
| [Today + 1]

Validating BCP-47 language tag using Java APIs

As far as I know, the only way to validate whether a given BCP-47 language tag is valid is to use the following idiom:
private static boolean isValid(String tag) {
try {
new Locale.Builder().setLanguageTag(tag).build();
return true;
} catch (IllformedLocaleException e) {
return false;
}
}
However, the downside of this approach is that setLanguageTag throws an exception which has noticeable (in a profile) performance overhead in workloads where locales are checked often.
The setLanguageTag function is implemented using sun.util.locale APIs, and as far as I can tell it's the only place where sun.util.locale.ParseStatus is checked.
What I would like to be able to do is to use a method which has the following semantics:
import sun.util.locale.LanguageTag;
import sun.util.locale.ParseStatus;
private static boolean isValid(String tag) {
ParseStatus sts = new ParseStatus();
LanguageTag.parse(tag, sts);
return !sts.isError();
}
However, it's not possible to check the locale in the above way since it's using sun.* classes directly since it requires additional JDK options to export sun.util.locale from the java.base module.
Is there a way to validate a language tag without using private sun.* APIs while being consistent with the implementation of sun.util.locale.LanguageTag#parse?
The simplest solution should be:
boolean isValidBCP47 = "und".equals(Locale.forLanguageTag(tag))
The best solution is to make use of java.util.Locale's filtering to handle this for you.
Often we need to fallback to locales. For example; en-JP is what you want for English Speakers visiting a theme park in Japan. However; when en-JP is not present you likely want to fall back to just en. In addition, your platform likely doesn't support every locale and would require a check against a list of supported locales.
Using com.glide.Locale you can do the following:
ArrayList<Locale.LanguageRange> priorityList = new ArrayList<>();
priorityList.add(new Locale.LanguageRange("en-JP"));
priorityList.add(new Locale.LanguageRange("joking")); // invalid tag
priorityList.add(new Locale.LanguageRange("fr")); // unsupported tag
priorityList.add(new Locale.LanguageRange("en"));
ArrayList<String> supportedTags = new ArrayList<>();
supportedTags.add("ja");
supportedTags.add("en-JP");
supportedTags.add("en");
Locale.filterTags(priorityList, supportedTags, Locale.FilteringMode.AUTOSELECT_FILTERING);
// returns ArrayList ["en-JP", "en"]

Writing forwards-compatible code when an API introduces a new exception type

One problem I've noticed when porting reflection code from Java 8 to Java 9+ is that setAccessible() now throws InaccessibleObjectException in addition to SecurityException when before in Java 8 InaccessibleObjectException wasn't an exception type.
What is the accepted way to write code that has to catch and handle an exception that it can't know about since it's in a future Java version yet still be compatible with the current version? (In this case the only ancestor class is RuntimeException, but that feels like a smell to me personally to write such an all-encompassing catch.)
You could ask the runtime for the Java version (as described in this post) and use exception.getClass().getName() to get the exception class name in a backward-compatible way
In other words
try {
method.setAccessible();
} catch (RuntimeException e) {
String version = (System.getProperty("java.version"))
String minorVersion = ver.split("\\.")[1];
if (minorVersion >=9) {
if (e.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) {
// Handle java 9 reflection access issue
} else {
// Handle java 8 runtime exception
}
}

Supressing console (disp) output for compiled MATLAB > Java program (using MATLAB Compiler)

Edit 2 After recieving a response from Mathworks support I've answered the question myself. In brief, there is an options class MWComponentOptions that is passed to the exported class when instantiated. This can, among other things, specify unique print streams for error output and regular output (i.e. from disp()-liked functions). Thanks for all the responses none the less :)
====================================================================
Just a quick question - is there any way to prevent MATLAB code from outputting to the Java console with disp (and similar) functions once compiled? What is useful debugging information in MATLAB quickly becomes annoying extra text in the Java logs.
The compilation tool I'm using is MATLAB Compiler (which I think is not the same as MATLAB Builder JA, but I might be wrong). I can't find any good documentation on the mcc command so am not sure if there are any options for this.
Of course if this is impossible and a direct consequence of the compiler converting all MATLAB code to its Java equivalent then that's completely understandable.
Thanks in advance
Edit This will also be useful to handle error reporting on the Java side alone - currently all MATLAB errors are sent to the console regardless of whether they are caught or not.
The isdeployed function returns true if run in a deployed application (with e.g. MATLAB Compiler or Builder JA) and false when running in live MATLAB.
You can surround your disp statements with an if isdeployed block.
I heard back from a request to Mathworks support, and they provided the following solution:
When creating whatever class has been exported, you can specify an MWComponentOptions object. This is poorly documented in R2012b, but for what I wanted the following example would work:
MWComponentOptions options = new MWComponentOptions();
PrintStream o = new PrintStream(new File("MATLAB log.log"));
options.setPrintStream(o); // send all standard dips() output to a log file
// the following ignores all error output (this will be caught by Java exception handling anyway)
options.setErrorStream((java.io.PrintStream)null);
// instantiate and use the exported class
myClass obj = new myClass(options);
obj.myMatlabFunction();
// etc...
Update
In case anyone does want to suppress all output, casing null to java.io.PrintStream ended up causing a NullPointerException in deployment. A better way to suppress all output is use to create a dummy print stream, something like:
PrintStream dummy = new PrintStream(new OutputStream() {
public void close() {}
public void flush() {}
public void write(byte[] b) {}
public void write(byte[] b, int off, int len) {}
public void write(int b) {}
} );
Then use
options.setErrorStream(dummy);
Hope this helps :)
Another possible hack if you have a stand-alone application and don't want to bother with classes at all:
Use evalc and deploy your func name during compile:
function my_wrap()
evalc('my_orig_func(''input_var'')');
end
And compile like
mcc -m my_wrap my_orig_func <...>
Well, it is obviously yet another hack.

blackberry method to replace strings?

so, again, due to blackberry's api limitation, i have 2 questions:
the response that i get back from my IOUtilities.streamToBytes(httpInput); call contains "<" characters. so what blackberry class/method can i use to replace my "<" with "<"? there is ONLY 1 replace() method in the String class and that method can only replace 1 character with another character. Again, since this is a blackberry project, i don't have access to anything above java 1.4
the response that i also get back from my IOUtilities.streamToBytes(httpInput); call begins with the usual soap response "<?xml version="1.0" encoding="utf-8" ?><string xmlns="http://www.mydomain.com">". any blackberry class/method that i can use to tell the program to ONLY RETURN everything between "<?xml version="1.0" encoding="utf-8" ?><string xmlns="http://www.mydomain.com">" AND "</string>"?
again, thanks to all of you for your help. much appreciated. i'm beginning to learn that developing in the blackberry environment is a bit tedious at times because certain java classes (that can make coding easier) are not available for use.
What you are encountering is being forced to use a J2ME profile based on an earlier J2SE release.
I have a replace utility method for strings that I wrote when targeting earlier platforms, that might be of use to you. But do note that what you really want is an XML parser; just replacing strings will only work if the XML is very simple.
static public String replace(String val, String fnd, String rpl, boolean igncas) {
int fl=(fnd==null ? 0 : fnd.length());
if(fl>0 && val.length()>=fl) {
StringBuffer sb=null; // string buffer
int xp=0; // index of previous fnd
for(int xa=0,mi=(val.length()-fl); xa<=mi; xa++) {
if(val.regionMatches(igncas,xa,fnd,0,fl)) {
if(xa>xp) { sb=append(sb,val.substring(xp,xa)); } // substring uses private construct which does not dup char[]
sb=append(sb,rpl);
xp=(xa+fl);
xa=(xp-1); // -1 to account for loop xa++;
}
}
if(sb!=null) {
if(xp<val.length()) { sb.append(val.substring(xp,val.length())); } // substring uses private construct which does not dup char[]
return sb.toString();
}
}
return val;
}
static private StringBuffer append(StringBuffer sb, String txt) {
if(sb==null) { sb=new StringBuffer(txt.length()); }
sb.append(txt);
return sb;
}
As to the second part of you question, you will need to use an XML parser to extract the information you want. Otherwise you will be in for some (probably kludgy) manual work.
A quick look at CLDC suggests it might be based on Java 1.1 (ugh!). DigiLife has a PDF document that has some more good information about J2ME.
Knowing which configuration (CDC or CLDC) and which profile (MIDP or PP) you are targeting is critical to knowing which APIs are available. And do note that even if you are using a profile based on J2SE 1.4, it might be missing all sorts of classes and methods, including the various XML parsing packages. Therefore you might have to provide alternatives yourself from a third party (or write them yourself).
EDIT: I note that the BlackBerry V5 doco does include XML parser packages.
Try this page:http://supportforums.blackberry.com/t5/Java-Development/String-Manipulation-split-replace-replaceAll/ta-p/620038
It supplies functions for some of the missing String functions in J2ME

Categories