Problems integrating Matlab with Java for deployment in web - java

I am seriously new to Matlab and Matlab Builder JA. I am trying to make a simple Java web by calling a Matlab functions. So, I have model.m file. I have put in the functions to be used as a library to run in a server and have some variables to be input by users, which are 'Time' (eg. 20) and 'Dose' (eg. 1 2 0 0). I have tried to integrate all the codes and include the Matlab library. But unfortunately, only the .html file can be run. Below are my codes and error that I get. Hope someone could help me to check whether I am compiling the model.m file correctly and the Java file is coded also correct. For your information, I am using Eclipse Kepler and Tomcat 7.0.54. Thanks in advance!
First of all, this is the error that I got when I run the application.
EDITED
HTTP Status 500-
java.lang.NullPointerException
com.mathworks.toolbox.javabuilder.internal.MWMCR.mclFeval(Native Method)
com.mathworks.toolbox.javabuilder.internal.MWMCR.access$600(MWMCR.java:23)
com.mathworks.toolbox.javabuilder.internal.MWMCR$6.mclFeval(MWMCR.java:833)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)
com.mathworks.toolbox.javabuilder.internal.MWMCR$5.invoke(MWMCR.java:731)
com.sun.proxy.$Proxy11.mclFeval(Unknown Source)
com.mathworks.toolbox.javabuilder.internal.MWMCR.invoke(MWMCR.java:406)
runPKmodelV1.Function.runPKmodelV1(Function.java:217)
SecondServlet.doGet(SecondServlet.java:78)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
This is the model.m file that have all the functions needed, with an output figure.
MATLAB model.m
function w = model(tf_sim,y0)
%%--------------------------------------------------------------------
% Running ODE model - Initial Conditions and setting up ode solver
%---------------------------------------------------------------------
%Initial Conditions:
%Initial Conditions:
% Dose_Central = 1;
% Drug_Central = 0;
% Dose_Peripheral = 0;
% Drug_Peripheral = 0;
%tf_sim=10; %Simulation time
% y0(1) = 1; % Dose in Central Compartment
% y0(2) = 0; % Drug in Central Compartment
% y0(3) = 0; % Dose in Peripheral Compartment
% y0(4) = 0; % Drug in Peripheral Compartment
options = odeset('RelTol',1e-4,'AbsTol',1e-5);
%%% Solving ODEs, final time = 2e+9 sec (aprox. 63 years) %%%
[t,y]=ode15s(#PK_Model_v1,[0 tf_sim],y0,options);
%%% Plotting state variables %%%
f = figure;
subplot(2,2,1);
plot(t,y(:,1),'r-');
subplot(2,2,2);
plot(t,y(:,2),'b-');
subplot(2,2,3);
plot(t,y(:,3),'m-');
subplot(2,2,4);
plot(t,y(:,4),'k-');
w = webfigure(f);
close(f);
end
function dy = PK_Model_v1(time,y)
%Parameter Values:
Tk0_Central = 1;
TLag_Central = 1;
Km_Central = 1;
Vm_Central = 30;
Tk0_Peripheral = 1;
TLag_Peripheral = 1;
Q12 = 1;
k12 = 1;
k21 = 1;
Central = 1;
Peripheral = 1;
ka_Central = 0.5;
ka_Peripheral = 0.1;
%Fluxes:
ReactionFlux1 = ka_Central*y(1);
ReactionFlux2 = Vm_Central*y(2)/(Km_Central+y(2));
ReactionFlux3 = ka_Peripheral*y(3);
ReactionFlux4 = (k12*y(2))*Central-(k21*y(4))*Peripheral;
dy(1,1) = -ReactionFlux1;
dy(2,1) = 1/Central*(ReactionFlux1 - ReactionFlux2 - ReactionFlux4);
dy(3,1) = -ReactionFlux3;
dy(4,1) = 1/Peripheral*(ReactionFlux3 + ReactionFlux4);
end
This is the welcome page, with all the variables to be input by users.
Eclipse page.html
<form action="SecondServlet">
<p> </p>
<p>PK Model Example</p>
<p> </p>
<p>Time</p>
<input type="text" name="tf_sim" value="" />
<p>Dosage</p>
<input type="text" name="y0" value="" />
<!-- Submit -->
<input type="submit" value="Display" name="DoPLot" />
<p> </p>
</form>
There is nothing in the index.jsp page. Only the webfigure after the submit button from page.html is clicked.
Eclipse index.jsp
<div ALIGN="CENTER">
<wf:web-figure root="WebFigures" name="Project_Figure" scope="session" />
</div>
This consists of codes used to get the data keyed in by the users and finally calculate the result with the use of Matlab library and dispatch the result into the index.jsp.
EDITED
Eclipse SecondServlet.java
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Object[] param = new MWArray[2];
Object[] result = null;
param[0] = new MWNumericArray(Integer.parseInt(request
.getParameter("tf_sim")), MWClassID.DOUBLE);
String[] str_elems = request.getParameter("y0").split("\\s+");
int[] numbers = new int[str_elems.length];
for (int i = 0; i < str_elems.length; i++) {
numbers[i] = Integer.parseInt(str_elems[i]);
}
try {
result = pkModel.model(1, param);
WebFigure webFig = (WebFigure) ((MWJavaObjectRef) result[0]).get();
// Set the figure scope to session
request.getSession().setAttribute("Project_Figure", webFig);
// Bind the figure's lifetime to session
request.getSession().setAttribute("Project_Figure_Binder",
new MWHttpSessionBinder(webFig));
updateSession(request.getSession(), result);
RequestDispatcher dispatcher = request
.getRequestDispatcher("/index.jsp");
dispatcher.forward(request, response);
} catch (MWException e) {
e.printStackTrace();
} finally {
MWArray.disposeArray(result);
}
}
public void updateSession(HttpSession session, Object[] param) {
int outputCount = param.length - 1;
session.setAttribute("numOutputs", outputCount);
}
Really hope someone could help. Thanks!

Take a look at the error message:
java.lang.NumberFormatException: For input string: "1 2 0 0"
java.lang.NumberFormatException.forInputString(Unknown Source)
java.lang.Integer.parseInt(Unknown Source)
java.lang.Integer.parseInt(Unknown Source)
SecondServlet.doGet(SecondServlet.java:70)
The first line states that the problem is the number format, the third tells us that it encounter the problem when using the parseInt method, and the last line tells us it's in the doGet method.
Taking a quick look at the doGet method, we see:
param[1] = new MWNumericArray(Integer.parseInt(request
.getParameter("y0")), MWClassID.DOUBLE);
Now, judging by your comments on the data format earlier y0 is meant to be an array of four numbers. The problem then is that Interger.parseInt is meant for parsing single numbers, not arrays of them.
To solve this you would need to add a separate step to split your input into individual numbers and parse them one at a time. Something like this:
String[] str_elems = request.getParameter("y0").split(" ");
List<Integer> int_elems = new LinkedList<Integer>();
for (int i = 0; i < str_elems.length; i++)
int_elems.add(Integer.parseInt(str_elems[i]));
Or something similar, modified to account for the input preferences of MWNumericArray, documentation for which I couldn't find.

Related

Why am I getting StringIndexOutOfBoundsException error in this substring method?

protected Void doInBackground(Void... voids) {
...
ABV = elem.select("td > span.muted").text();
Log.d("myLOG_ABV", ABV);
Log.d("myLOG_ABVlength", String.valueOf(ABV.length()));
/*String temp_ABV = ABV.substring(ABV.length()-6, ABV.length());*/
... }
Result
D/myLOG_ABV: Russian River Brewing Company American Wild Ale | 7.50%
D/myLOG_ABVlength: 55
and then, I cancled the annotation code.
...
ABV = elem.select("td > span.muted").text();
Log.d("myLOG_ABV", ABV);
Log.d("myLOG_ABVlength", String.valueOf(ABV.length()));
***String temp_ABV = ABV.substring(ABV.length()-6, ABV.length());***
...
Result
Caused by: java.lang.StringIndexOutOfBoundsException: length=0;
index=-6
Why am I getting StringIndexOutOfBoundsException error in this substring method?
I got the result that 'ABVlength : 55' in my code with annotation.
But after cancellation of annotation, I got StringIndexOutOfBoundsException.
Seriously, I am fighting with this code for 7hours 30minutes.
So we have:
***String temp_ABV = ABV.substring(ABV.length()-6, ABV.length());***
Caused by: java.lang.StringIndexOutOfBoundsException: length=0; index=-6
How can you get an index of -6 in this situation? ABV must have zero length, i.e. "".
It may be the case that ABV should have at least six characters, but that indicates a bug elsewhere.
What to do?
First and foremost, validate your inputs.
Somewhere you would normally want something like:
if (abv.length() < 6) {
throw new IllegalArgumentException("...");
}
Next find where that value is coming from and fix the bug.
Looks like you're parsing some kind of external document. In this case you may want the handling to be more lenient:
int abvLen = abv.length();
int abvEndIndex = abvLen - 6;
if (abvEndIndex < 0) {
log.error("ABV length less than 6", abv);
abvEndIndex = 0;
}
String abvEnd = abv.substring(abvEndIndex, abvLen);

Preventing Vue from looping

I have three fields
hour -- minutes -- and total
If hour or minutes change i want to calculate a total.
If the total is changed i want to calculate the corresponding minutes and hours.
Example:
1h 30minutes = 1.5 Total
2.25 Total = 2h 15minutes
I am trying to achive this with watch
watch: {
hour: {
handler: (new_hour, old_hour) => {
if(isNaN(new_hour)){
manual.hour = old_hour
}else{
manual.setTotal();
}
}
},
minutes: {
handler: (new_minutes, old_minutes) => {
if(isNaN(new_minutes)){
manual.minutes = old_minutes
}else{
if(Number(new_minutes) > 60){
manual.minutes = old_minutes
}else{
manual.setTotal();
}
}
}
},
total:{
handler: (new_total, old_total) => {
if(isNaN(new_total)) {
manual.total = old_total;
}else{
const hour = new_total.split(",")[0];
const minutes = new_total.split(",")[1];
manual.hour = hour;
manual.minutes = (minutes * 60).toFixed(0);
}
}
}
}
However this is resulting in a loop because on handler allways calls the other handler. How can this be done in a smarter way?
you could use onkeyup listener (and/or change)
new Vue({
el: "#app",
data: {
input_h: 0,
input_m: 0,
input_t: 0
},
methods: {
update_h (e) {
this.input_h = Number(e.target.value)
this.update_t(null)
},
update_m (e) {
this.input_m = Number(e.target.value)
this.update_t(null)
},
update_t (e) {
if (e === null) {
this.input_t = Math.round((this.input_h + this.input_m / 60) * 100)/100
} else {
this.input_t = Number(e.target.value)
this.input_h = Math.floor(this.input_t)
this.input_m = Math.round(this.input_t%1 * 60)
}
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.js"></script>
<div id="app">
<input :value="input_h" #keyUp="update_h"/>Hours<br/>
<input :value="input_m" #keyUp="update_m"/>Minutes<br/>
<input :value="input_t" #keyUp="update_t"/>Total<br/>
</div>
Otherwise, if you want to prevent circular dependency, you need to set up a single source of data, and use computed getters and setters to update the other fields. You don't even have to use a visible field for that.
https://jsbin.com/tagupab/edit has a working example
I haven't checked this out, but perhaps you could exchange watchers for computed properties with setter, see ref Computed setter
Note the comment here circular dependency on observed properties #622 (yyx990803 commented on Dec 11, 2014)
The thing is even when there is a circular dependency, the eventual
value should be able to stabilize after 1 additional iteration (which
Vue will then stop because the new evaluated value is the same)
OR
I guess you could put
if (newValue === oldValue) {
return
}
at the top of each watcher. This is sort of what computed does anyway.

Start Java Application using System.Diagnostics.Process

$startCount = 5;
$processors = Get-WmiObject -Class Win32_ComputerSystem | select -
ExpandProperty "NumberOfLogicalProcessors";
$perInstance = $processors / $startCount;
$affinityloop = 1;
$affinityvalue = 0;
for($i=1; $i -le $startCount; $i++) {
$affinityvalue = 0;
for($u=1; $u -le $perInstance ; $u++) {
$affinityvalue = $affinityvalue + $affinityloop;
$affinityloop = $affinityloop * 2;
}
$ps = new-object System.Diagnostics.Process;
$ps.StartInfo.Filename = "C:\jdk\bin\java.exe";
$ps.StartInfo.Arguments = " -server -Xms10240m -Xmx10240m -XX:+UseG1GC -cp `".;*`" Worker";
$ps.start();
Write-Host $affinityvalue ;
$ps.ProcessorAffinity = [Convert]::ToString($affinityvalue, 16);
}
I am trying to start a Windows Java application on two different NUMA nodes. Has anyone able to accomplish this with Diagnostics.Process format? This code does work fine, but all applications created are on the same NUMA node and hence only using 50% power.
I tried codes such as $mod = ($i % 2); to help prepare for some way to alternate the NUMA node but unsure how to specify it within the script.
EDIT
Tried to load balance with ProcessorAffinity and I get crashes due to Double unable to convert to IntPtr
EDIT 2
So it looks like Windows Groups the processors past 64 into Groups. Can't seem to find a way to alter that like ProcessAffinity. I guess its just not that common. You can easily do it in Task manager, just need to find a way to do it in Powershell or similar.

Log producer object in Scala

I am new to scala and java altogether and trying to run a sample producer code. All it does is, takes some raw products and referrers stored in csv files and uses rnd to generate some random log. Following is my code:
object LogProducer extends App {
//WebLog config
val wlc = Settings.WebLogGen
val Products = scala.io.Source.fromInputStream(getClass.getResourceAsStream("/products.csv")).getLines().toArray
val Referrers = scala.io.Source.fromInputStream(getClass.getResourceAsStream("/referrers.csv")).getLines().toArray
val Visitors = (0 to wlc.visitors).map("Visitors-" + _)
val Pages = (0 to wlc.pages).map("Pages-" + _)
val rnd = new Random()
val filePath = wlc.filePath
val fw = new FileWriter(filePath, true)
//adding randomness to time increments for demo
val incrementTimeEvery = rnd.nextInt(wlc.records - 1) + 1
var timestamp = System.currentTimeMillis()
var adjustedTimestamp = timestamp
for (iteration <- 1 to wlc.records) {
adjustedTimestamp = adjustedTimestamp + ((System.currentTimeMillis() - timestamp) * wlc.timeMultiplier)
timestamp = System.currentTimeMillis()
val action = iteration % (rnd.nextInt(200) + 1) match {
case 0 => "purchase"
case 1 => "add_to_cart"
case _ => "page_view"
}
val referrer = Referrers(rnd.nextInt(Referrers.length - 1))
val prevPage = referrer match {
case "Internal" => Pages(rnd.nextInt(Pages.length - 1))
case _ => ""
}
val visitor = Visitors(rnd.nextInt(Visitors.length - 1))
val page = Pages(rnd.nextInt(Pages.length - 1))
val product = Products(rnd.nextInt(Products.length - 1))
val line = s"$adjustedTimestamp\t$referrer\t$action\t$prevPage\t$visitor\t$page\t$product\n"
fw.write(line)
if (iteration % incrementTimeEvery == 0) {
//os.flush()
println(s"Sent $iteration messages!")
val sleeping = rnd.nextInt(incrementTimeEvery * 60)
println(s"Sleeping for $sleeping ms")
}
}
}
It is pretty straightforward where it is basically generating some variables and adding it to the line.
However I am getting a big exception error stack which i am not able to understand:
"C:\Program Files\Java\jdk1.8.0_92\bin\java...
Exception in thread "main" java.nio.charset.MalformedInputException: Input length = 1
at java.nio.charset.CoderResult.throwException(CoderResult.java:281)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:339)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at scala.io.BufferedSource$BufferedLineIterator.hasNext(BufferedSource.scala:70)
at scala.collection.Iterator.foreach(Iterator.scala:929)
at scala.collection.Iterator.foreach$(Iterator.scala:929)
at scala.collection.AbstractIterator.foreach(Iterator.scala:1417)
at scala.collection.generic.Growable.$plus$plus$eq(Growable.scala:59)
at scala.collection.generic.Growable.$plus$plus$eq$(Growable.scala:50)
at scala.collection.mutable.ArrayBuffer.$plus$plus$eq(ArrayBuffer.scala:104)
at scala.collection.mutable.ArrayBuffer.$plus$plus$eq(ArrayBuffer.scala:48)
at scala.collection.TraversableOnce.to(TraversableOnce.scala:310)
at scala.collection.TraversableOnce.to$(TraversableOnce.scala:308)
at scala.collection.AbstractIterator.to(Iterator.scala:1417)
at scala.collection.TraversableOnce.toBuffer(TraversableOnce.scala:302)
at scala.collection.TraversableOnce.toBuffer$(TraversableOnce.scala:302)
at scala.collection.AbstractIterator.toBuffer(Iterator.scala:1417)
at scala.collection.TraversableOnce.toArray(TraversableOnce.scala:289)
at scala.collection.TraversableOnce.toArray$(TraversableOnce.scala:283)
at scala.collection.AbstractIterator.toArray(Iterator.scala:1417)
at clickstream.LogProducer$.delayedEndpoint$clickstream$LogProducer$1(logProducer.scala:16)
at clickstream.LogProducer$delayedInit$body.apply(logProducer.scala:12)
at scala.Function0.apply$mcV$sp(Function0.scala:34)
at scala.Function0.apply$mcV$sp$(Function0.scala:34)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App.$anonfun$main$1$adapted(App.scala:76)
at scala.collection.immutable.List.foreach(List.scala:389)
at scala.App.main(App.scala:76)
at scala.App.main$(App.scala:74)
at clickstream.LogProducer$.main(logProducer.scala:12)
at clickstream.LogProducer.main(logProducer.scala)
Process finished with exit code 1
Can someone please help me identify what the exception mean? Thanks all
So it wasnt hard.. it was my amateurish knowledge. It was a simple IO exception where Intellij wasnt able to get the values from my csv file. When i imported it into resources root directory, it gave me a warning message of wrong encoding.
The error was at this point:
val Products = scala.io.Source.fromInputStream(getClass.getResourceAsStream("/products.csv")).getLines().toArray
thanks for efforts though
It was an encoding issue, for Scala a quick fix would be:
replace:
val Products=scala.io.Source.fromInputStream(getClass.getResourceAsStream("/products.csv")).getLines().toArray
val Referrers = scala.io.Source.fromInputStream(getClass.getResourceAsStream("/referrers.csv")).getLines().toArray
using this:
val Products=scala.io.Source.fromInputStream(getClass.getResourceAsStream("/products.csv"))("UTF-8").getLines().toArray
val Referrers = scala.io.Source.fromInputStream(getClass.getResourceAsStream("/referrers.csv"))("UTF-8").getLines().toArray
For java and more details please check out this link: http://biercoff.com/malformedinputexception-input-length-1-exception-solution-for-scala-and-java/

Cannot find exception's cause [duplicate]

I made a color palette with a jPanel and a JLabel array in it. At first it worked well, but then i put some other jLabels out of the JPanel and added them some events. Now I keep getting this error:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeLo(TimSort.java:747)
at java.util.TimSort.mergeAt(TimSort.java:483)
at java.util.TimSort.mergeCollapse(TimSort.java:410)
at java.util.TimSort.sort(TimSort.java:214)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at java.util.Collections.sort(Collections.java:217)
at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(SortingFocusTraversalPolicy.java:136)
at javax.swing.SortingFocusTraversalPolicy.getFocusTraversalCycle(SortingFocusTraversalPolicy.java:110)
at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(SortingFocusTraversalPolicy.java:435)
at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(LayoutFocusTraversalPolicy.java:166)
at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(SortingFocusTraversalPolicy.java:515)
at java.awt.FocusTraversalPolicy.getInitialComponent(FocusTraversalPolicy.java:169)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:380)
at java.awt.Component.dispatchEventImpl(Component.java:4731)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:723)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:682)
at java.awt.EventQueue$3.run(EventQueue.java:680)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:696)
at java.awt.EventQueue$4.run(EventQueue.java:694)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:693)
at java.awt.SequencedEvent.dispatch(SequencedEvent.java:116)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:721)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:682)
at java.awt.EventQueue$3.run(EventQueue.java:680)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:696)
at java.awt.EventQueue$4.run(EventQueue.java:694)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:693)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)
I tried to remove everything i've done after first time i got this error, but still keep getting it. When i change the layout from GridLayout to anything else, then the error disappears, but the code becomes useless. So i need GridLayout. When i move everything in that JPanel to another JPanel, the error also goes away. But when i remove the first JPanel, error comes back.
By the way, the program works, but it's not pleasent to keep getting errors...
Edit: When i use less than 225 color, there's no error. I'm really curious about what's happening. Any explanation would be appreciated...
It seems to me like you've hit a bug in the JDK since the error seems to come from Swing classes.
Options:
Define the property java.util.Arrays.useLegacyMergeSort as true. Either using in your code the line
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
before any Swing code. As the first line in the main method should work.
Or adding
-Djava.util.Arrays.useLegacyMergeSort=true
to your starting options (in the console, or in the project properties in an IDE, Ant script, etc.)
Upgrade your JDK and see if the problem goes away
Downgrade to Java 6
Report my findings:
-Djava.util.Arrays.useLegacyMergeSort=true
works
but
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
does not work.
It is due to the fact that in JDK Arrays.class
static final class LegacyMergeSort {
private static final boolean userRequested = ...
It is a static variable which is defined when jvm starts. Setting System property in the program will have no effect if the class has been loaded into jvm.
I have beeing monitoring the LegacyMergeSort.userRequested variable, and the findings confirmed with above statement.
Update:
The program must set system properties before java.util.Arrays is loaded to classloader.
Otherwise, once it is loaded, setting the properties is not going to be useful due to the reason mentioned above.
Make sure nothing else loaded Arrays.class:
By putting following code to your program to test:
java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[] { String.class });
m.setAccessible(true);
ClassLoader cl = ClassLoader.getSystemClassLoader();
Object test1 = m.invoke(cl, "java.util.Arrays");
System.out.println("test1 loaded? ->" + (test1 != null));
[Update]
This solution unfortunately is not guaranteed to solve the problem in all cases. It is not enough to patch the default SortingFocusTraversalPolicy
of the KeyboardFocusManager.
I recommend to read the answer by Robin Loxley below, including his Update.
[/Update]
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:868)
This problem is caused by a bug in javax.swing.LayoutComparator.
The following class installs a fixed version of javax.swing.LayoutComparator, which does not violate the contract of Comparator<Component>. This (or any other) fixed version of javax.swing.LayoutComparator should be submitted to Oracle by some Oracle contributor.
package ...;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.FocusTraversalPolicy;
import java.awt.KeyboardFocusManager;
import java.awt.Window;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.ListIterator;
import javax.swing.JRootPane;
import javax.swing.SortingFocusTraversalPolicy;
import javax.swing.UIManager;
/**
* Uses reflection to install a fixed version of {#link javax.swing.LayoutComparator} to solve the
* LayoutFocusTraversalPolicy/TimSort problem.
*
* <p>
* <code>java.lang.IllegalArgumentException: Comparison method violates its general contract!</code>
* <br/>
* {#code at java.util.TimSort.mergeHi(TimSort.java:868)}
* </p>
* <p>
* Usage: call {#code Class.forName(LayoutFocusTraversalPolicyTimSortBugFixer.class.getName())}
* before creating Swing components.
* </p>
*
* #author Burkhard Strauss
* #since Feb 2015
*/
public class LayoutFocusTraversalPolicyTimSortBugFixer
{
static
{
UIManager.getUI(new JRootPane()); // make Swing install the SortingFocusTraversalPolicy
final KeyboardFocusManager keyboardFocusManager = KeyboardFocusManager
.getCurrentKeyboardFocusManager();
final FocusTraversalPolicy focusTraversalPolicy = keyboardFocusManager
.getDefaultFocusTraversalPolicy();
boolean fixed = false;
if (focusTraversalPolicy instanceof SortingFocusTraversalPolicy)
{
try
{
final Field field = SortingFocusTraversalPolicy.class.getDeclaredField("comparator");
final boolean accessible = field.isAccessible();
try
{
field.setAccessible(true);
field.set(focusTraversalPolicy, new LayoutComparator());
fixed = true;
}
finally
{
field.setAccessible(accessible);
}
}
catch (final Exception e)
{
}
}
if (!fixed)
{
Loggers.getLoggerFor(LayoutFocusTraversalPolicyTimSortBugFixer.class).warn("could not fix the bug");
}
}
/**
* Fixed version of {#link javax.swing.LayoutComparator}.
* <p>
* Search for 'bugfix' in the code.
* </p>
*
* #author Burkhard Strauss
* #since Feb 2015
*/
#SuppressWarnings("serial")
private static class LayoutComparator implements Comparator<Component>, java.io.Serializable
{
private static final int ROW_TOLERANCE = 10;
private boolean horizontal = true;
private boolean leftToRight = true;
#SuppressWarnings("unused")
void setComponentOrientation(final ComponentOrientation orientation)
{
horizontal = orientation.isHorizontal();
leftToRight = orientation.isLeftToRight();
}
#Override
public int compare(Component a, Component b)
{
if (a == b)
{
return 0;
}
// Row/Column algorithm only applies to siblings. If 'a' and 'b'
// aren't siblings, then we need to find their most inferior
// ancestors which share a parent. Compute the ancestory lists for
// each Component and then search from the Window down until the
// hierarchy branches.
if (a.getParent() != b.getParent())
{
final LinkedList<Component> aAncestory = new LinkedList<Component>();
for (; a != null; a = a.getParent())
{
aAncestory.add(a);
if (a instanceof Window)
{
break;
}
}
if (a == null)
{
// 'a' is not part of a Window hierarchy. Can't cope.
throw new ClassCastException();
}
final LinkedList<Component> bAncestory = new LinkedList<Component>();
for (; b != null; b = b.getParent())
{
bAncestory.add(b);
if (b instanceof Window)
{
break;
}
}
if (b == null)
{
// 'b' is not part of a Window hierarchy. Can't cope.
throw new ClassCastException();
}
for (ListIterator<Component> aIter = aAncestory.listIterator(aAncestory.size()), bIter = bAncestory
.listIterator(bAncestory.size());;)
{
if (aIter.hasPrevious())
{
a = aIter.previous();
}
else
{
// a is an ancestor of b
return -1;
}
if (bIter.hasPrevious())
{
b = bIter.previous();
}
else
{
// b is an ancestor of a
return 1;
}
if (a != b)
{
break;
}
}
}
final int ax = a.getX(), ay = a.getY(), bx = b.getX(), by = b.getY();
int zOrder = a.getParent().getComponentZOrder(a) - b.getParent().getComponentZOrder(b);
{
//
// Here is the bugfix:
// Don't return 0 if a != b. This would violate the contract of
// Comparator<Component>.compare().
//
if (zOrder == 0)
{
zOrder = -1;
}
}
if (horizontal)
{
if (leftToRight)
{
// LT - Western Europe (optional for Japanese, Chinese, Korean)
if (Math.abs(ay - by) < ROW_TOLERANCE)
{
return (ax < bx) ? -1 : ((ax > bx) ? 1 : zOrder);
}
else
{
return (ay < by) ? -1 : 1;
}
}
else
{ // !leftToRight
// RT - Middle East (Arabic, Hebrew)
if (Math.abs(ay - by) < ROW_TOLERANCE)
{
return (ax > bx) ? -1 : ((ax < bx) ? 1 : zOrder);
}
else
{
return (ay < by) ? -1 : 1;
}
}
}
else
{ // !horizontal
if (leftToRight)
{
// TL - Mongolian
if (Math.abs(ax - bx) < ROW_TOLERANCE)
{
return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder);
}
else
{
return (ax < bx) ? -1 : 1;
}
}
else
{ // !leftToRight
// TR - Japanese, Chinese, Korean
if (Math.abs(ax - bx) < ROW_TOLERANCE)
{
return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder);
}
else
{
return (ax > bx) ? -1 : 1;
}
}
}
}
}
}
I just ran into the same error and spent a good amount of time tracking it down. To help others who run into this error it is important to know how to test TimSort. The checks that violate the transitivity contract and throw this error are deep in the algorithm and require a test to meet certain criteria before this problem can be reproduced.
Create a list with 32 or more objects.
Within that list, there needs to two or more runs.
Each run must contain 3 or more objects.
Once you meet those two criteria you can begin testing for this failure.
A run is defined as a sub-set of the list where each item is already in the desired ordered state.
It is not enough to patch LayoutComparator as suggerested above. This fix does not work in my case.
The issue was fixed in JDK 8 (8u45 at least).
SortingFocusTraversalPolicy to use legacy Merge Sort Method.
There is nothing wrong with the JDK.
I was facing the same issue since 2 days & finally got to know that bug was with my date-format.
In my API response few dates were in "dd-MM-yyyy HH:mm" format while few of them were in "dd/MM/yyyy HH:mm" format.
Same issue while comparing integers, May be your List is having some null values.
Here is my code, which is working like a charm
Collections.sort(root_array, new Comparator<RootResponseItem>(){
public int compare(RootResponseItem o1, RootResponseItem o2){
Date date1 = new Date();
String dtStart = o1.getSectors().get(0).getDeparture().getDate() + " " + o1.getSectors().get(0).getDeparture().getTime();
dtStart = dtStart.replaceAll("-","/");
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
try {
date1 = format.parse(dtStart);
} catch (ParseException e) {
e.printStackTrace();
}
Date date2 = new Date();
String dtStart2 = o2.getSectors().get(0).getDeparture().getDate() + " " + o2.getSectors().get(0).getDeparture().getTime();
dtStart2 = dtStart2.replaceAll("-","/");
SimpleDateFormat format2 = new SimpleDateFormat("dd/MM/yyyy HH:mm");
try {
date2 = format2.parse(dtStart2);
} catch (ParseException e) {
e.printStackTrace();
}
return date1.compareTo(date2);
}
});

Categories

Resources