Bug 295122 - [refactoring] java.lang.IllegalArgumentException: Illegal pattern character 'j'
Summary: [refactoring] java.lang.IllegalArgumentException: Illegal pattern character 'j'
Status: VERIFIED FIXED
Alias: None
Product: JDT
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.4.2   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 3.6 M6   Edit
Assignee: Markus Keller CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 299049
Blocks:
  Show dependency tree
 
Reported: 2009-11-13 16:20 EST by frankar CLA
Modified: 2010-02-10 04:59 EST (History)
2 users (show)

See Also:


Attachments
Fix for HEAD (9.52 KB, patch)
2010-01-13 09:32 EST, Markus Keller CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description frankar CLA 2009-11-13 16:20:08 EST
User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Build Identifier: M20090211-1700

Translation problem 
This is an eclipse bug.  SimpleDateFormat uses a series of characters to describe how the date is viewed.  These are the valid characters (all other non-quoted alphabetic characters are reserved):


RD/z (GERMAN) looks up a date format from a language specific properties file.  For English the values are:

RefactoringHistoryLabelProvider_label_country=US
RefactoringHistoryLabelProvider_label_language=en
RefactoringHistoryLabelProvider_this_week_format=w
RefactoringHistoryLabelProvider_last_week_format=w
RefactoringHistoryLabelProvider_this_month_format=MMMMM yyyy
RefactoringHistoryLabelProvider_last_month_format=MMMMM yyyy
RefactoringHistoryLabelProvider_label_variant=
RefactoringHistoryLabelProvider_week_format=w
RefactoringHistoryLabelProvider_year_format=yyyy
RefactoringHistoryLabelProvider_month_format=MMMMM
RefactoringHistoryLabelProvider_day_format=EEEE

all of which are valid.  For German they were translated to the following:

RefactoringHistoryLabelProvider_label_country=DE
RefactoringHistoryLabelProvider_label_language=de
RefactoringHistoryLabelProvider_this_week_format=w
RefactoringHistoryLabelProvider_last_week_format=w
RefactoringHistoryLabelProvider_this_month_format=MMMMM jjjj
RefactoringHistoryLabelProvider_last_month_format=MMMMM jjjj
RefactoringHistoryLabelProvider_week_format=w
RefactoringHistoryLabelProvider_year_format=jjjj
RefactoringHistoryLabelProvider_month_format=MMMMM
RefactoringHistoryLabelProvider_day_format=EEEE

of which j is invalid.  I would submit this to eclipse's bug tracking site.  The translations project is called babel.  

Reproducible: Always

Steps to Reproduce:
1.Bring up RD/z in German 
2. create local project 
3. RMC on project -> properties ( GERMAN: EIGENSCHAFTEN) select Refactoring History
exception occurs
it could be that there has to be a change first made to the local project - like delete a source in order to get an entry in Refactoring History.
Comment 1 Paul Webster CLA 2009-11-16 08:00:14 EST
Please post the full stack trace of the exception.

PW
Comment 2 frankar CLA 2009-11-16 10:03:04 EST
ENTRY org.eclipse.jface 4 2 2009-11-05 14:15:11.460
!MESSAGE Beim Aufrufen des Codes aus dem Plug-in "org.eclipse.jface" sind Fehler aufgetreten.
!STACK 0
java.lang.IllegalArgumentException: Illegal pattern character 'j'
	at java.text.SimpleDateFormat.compile(Unknown Source)
	at java.text.SimpleDateFormat.initialize(Unknown Source)
	at java.text.SimpleDateFormat.<init>(Unknown Source)
	at org.eclipse.ltk.ui.refactoring.history.RefactoringHistoryLabelProvider.getText(Unknown Source)
	at org.eclipse.ltk.internal.ui.refactoring.history.BrowseRefactoringHistoryLabelProvider.getText(Unknown Source)
	at org.eclipse.jface.viewers.WrappedViewerLabelProvider.getText(Unknown Source)
	at org.eclipse.jface.viewers.WrappedViewerLabelProvider.update(Unknown Source)
	at org.eclipse.jface.viewers.ViewerColumn.refresh(Unknown Source)
	at org.eclipse.jface.viewers.AbstractTreeViewer.doUpdateItem(Unknown Source)
	at org.eclipse.jface.viewers.AbstractTreeViewer$UpdateItemSafeRunnable.run(Unknown Source)
	at org.eclipse.core.runtime.SafeRunner.run(Unknown Source)
	at org.eclipse.core.runtime.Platform.run(Unknown Source)
	at org.eclipse.ui.internal.JFaceUtil$1.run(Unknown Source)
	at org.eclipse.jface.util.SafeRunnable.run(Unknown Source)
	at org.eclipse.jface.viewers.AbstractTreeViewer.doUpdateItem(Unknown Source)
	at org.eclipse.jface.viewers.StructuredViewer$UpdateItemSafeRunnable.run(Unknown Source)
	at org.eclipse.core.runtime.SafeRunner.run(Unknown Source)
	at org.eclipse.core.runtime.Platform.run(Unknown Source)
	at org.eclipse.ui.internal.JFaceUtil$1.run(Unknown Source)
	at org.eclipse.jface.util.SafeRunnable.run(Unknown Source)
	at org.eclipse.jface.viewers.StructuredViewer.updateItem(Unknown Source)
	at org.eclipse.jface.viewers.AbstractTreeViewer.createTreeItem(Unknown Source)
	at org.eclipse.jface.viewers.AbstractTreeViewer$1.run(Unknown Source)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(Unknown Source)
	at org.eclipse.jface.viewers.AbstractTreeViewer.createChildren(Unknown Source)
	at org.eclipse.jface.viewers.TreeViewer.createChildren(Unknown Source)
	at org.eclipse.jface.viewers.AbstractTreeViewer.internalInitializeTree(Unknown Source)
	at org.eclipse.jface.viewers.TreeViewer.internalInitializeTree(Unknown Source)
	at org.eclipse.jface.viewers.AbstractTreeViewer$5.run(Unknown Source)
	at org.eclipse.jface.viewers.StructuredViewer.preservingSelection(Unknown Source)
	at org.eclipse.jface.viewers.TreeViewer.preservingSelection(Unknown Source)
	at org.eclipse.jface.viewers.StructuredViewer.preservingSelection(Unknown Source)
	at org.eclipse.jface.viewers.AbstractTreeViewer.inputChanged(Unknown Source)
	at org.eclipse.jface.viewers.ContentViewer.setInput(Unknown Source)
	at org.eclipse.jface.viewers.StructuredViewer.setInput(Unknown Source)
	at org.eclipse.ltk.internal.ui.refactoring.history.RefactoringHistoryControl.setInput(Unknown Source)
	at org.eclipse.ltk.internal.ui.refactoring.history.SortableRefactoringHistoryControl.setInput(Unknown Source)
	at org.eclipse.ltk.internal.ui.refactoring.history.ShowRefactoringHistoryControl.setInput(Unknown Source)
	at org.eclipse.ltk.internal.ui.refactoring.history.RefactoringPropertyPage$5.run(Unknown Source)
	at org.eclipse.jface.operation.ModalContext.runInCurrentThread(Unknown Source)
	at org.eclipse.jface.operation.ModalContext.run(Unknown Source)
	at org.eclipse.jface.window.ApplicationWindow$1.run(Unknown Source)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(Unknown Source)
	at org.eclipse.jface.window.ApplicationWindow.run(Unknown Source)
	at org.eclipse.ui.internal.WorkbenchWindow.run(Unknown Source)
	at org.eclipse.ltk.internal.ui.refactoring.history.RefactoringPropertyPage.handleInputEvent(Unknown Source)
	at org.eclipse.ltk.internal.ui.refactoring.history.RefactoringPropertyPage.createContents(Unknown Source)
	at org.eclipse.jface.preference.PreferencePage.createControl(Unknown Source)
	at org.eclipse.jface.preference.PreferenceDialog.createPageControl(Unknown Source)
	at org.eclipse.jface.preference.PreferenceDialog$14.run(Unknown Source)
	at org.eclipse.core.runtime.SafeRunner.run(Unknown Source)
	at org.eclipse.core.runtime.Platform.run(Unknown Source)
	at org.eclipse.ui.internal.JFaceUtil$1.run(Unknown Source)
	at org.eclipse.jface.util.SafeRunnable.run(Unknown Source)
	at org.eclipse.jface.preference.PreferenceDialog.showPage(Unknown Source)
	at org.eclipse.ui.internal.dialogs.FilteredPreferenceDialog.showPage(Unknown Source)
	at org.eclipse.jface.preference.PreferenceDialog$10.run(Unknown Source)
	at org.eclipse.swt.custom.BusyIndicator.showWhile(Unknown Source)
	at org.eclipse.jface.preference.PreferenceDialog$9.selectionChanged(Unknown Source)
	at org.eclipse.jface.viewers.StructuredViewer$3.run(Unknown Source)
	at org.eclipse.core.runtime.SafeRunner.run(Unknown Source)
	at org.eclipse.core.runtime.Platform.run(Unknown Source)
	at org.eclipse.ui.internal.JFaceUtil$1.run(Unknown Source)
	at org.eclipse.jface.util.SafeRunnable.run(Unknown Source)
	at org.eclipse.jface.viewers.StructuredViewer.firePostSelectionChanged(Unknown Source)
	at org.eclipse.jface.viewers.StructuredViewer.handlePostSelect(Unknown Source)
	at org.eclipse.jface.viewers.StructuredViewer$5.widgetSelected(Unknown Source)
	at org.eclipse.jface.util.OpenStrategy.firePostSelectionEvent(Unknown Source)
	at org.eclipse.jface.util.OpenStrategy.access$4(Unknown Source)
	at org.eclipse.jface.util.OpenStrategy$3.run(Unknown Source)
	at org.eclipse.swt.widgets.RunnableLock.run(Unknown Source)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Unknown Source)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Unknown Source)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
	at org.eclipse.jface.window.Window.runEventLoop(Unknown Source)
	at org.eclipse.jface.window.Window.open(Unknown Source)
	at org.eclipse.ui.dialogs.PropertyDialogAction.run(Unknown Source)
	at org.eclipse.jface.action.Action.runWithEvent(Unknown Source)
	at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(Unknown Source)
	at org.eclipse.jface.action.ActionContributionItem.access$2(Unknown Source)
	at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(Unknown Source)
	at org.eclipse.swt.widgets.EventTable.sendEvent(Unknown Source)
	at org.eclipse.swt.widgets.Widget.sendEvent(Unknown Source)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Unknown Source)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Unknown Source)
	at org.eclipse.ui.internal.Workbench.runUI(Unknown Source)
	at org.eclipse.ui.internal.Workbench.access$4(Unknown Source)
	at org.eclipse.ui.internal.Workbench$5.run(Unknown Source)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Unknown Source)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Unknown Source)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(Unknown Source)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(Unknown Source)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(Unknown Source)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(Unknown Source)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(Unknown Source)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(Unknown Source)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Unknown Source)
	at org.eclipse.equinox.launcher.Main.basicRun(Unknown Source)
	at org.eclipse.equinox.launcher.Main.run(Unknown Source)
	at org.eclipse.equinox.launcher.Main.main(Unknown Source)
Comment 3 Paul Webster CLA 2009-11-16 10:15:38 EST
Your error is because simple date formatter doesn't accept 'j', and this is coming from the JDK.  Please use only SDF approved patterns (the locale will determine how those patterns are interpretted).

PW
Comment 4 frankar CLA 2009-12-19 10:43:55 EST
last update from eclipse was:
Can you check the code which creates the SimpleDateFormat in org.eclipse  
.ltk.ui.refactoring.history.RefactoringHistoryLabelProvider.getText does  
so in the same way ?                                                      
                                                                          
                                                                          
I looked at it  and it does                                               
                                                                          
format= new                                                               
SimpleDateFormat(RefactoringUIMessages.RefactoringHistoryLabelProvider_t  
his_week_format, fCurrentLocale);                                         
format= new                                                               
SimpleDateFormat(RefactoringUIMessages.RefactoringHistoryLabelProvider_y  
ear_format, fCurrentLocale);                                              
                                                                         
http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.ltk.ui.refactoring/  
src/org/eclipse/ltk/ui/refactoring/history/RefactoringHistoryLabelProvid  
er.java?view=markup                                                       
                                                                          

*******************************************
RD/z dev and Java L3 investigated the exception further:
 the problem lies within the translated property page, which contains an
invalid character ('j') for the constructor that's used in the          
code.                                                                   
                                                                        
I suspect the format strings are never seen by the user (so don't need  
translating) and are only used in code such as format= new              
SimpleDateFormat(RefactoringUIMessages.RefactoringHistoryLabelProvider_y
ear_format, fCurrentLocale); which (in this instance) equates to format=
new SimpleDateFormat("jjjj", Locale.GERMAN); that line of code will     
always throw IllegalArgumentException: Illegal pattern character 'j' as 
will format= new SimpleDateFormat("uuuu", Locale.GERMAN); even though   
'u' is a valid character in the default DateFormatSymbols for           
Locale.GERMAN.                                                          
                                                                        
When the SimpleDateFormat(String, Locale) constructor is used the string
can only contain characters from the table in the API namely            
"GyMdkHmsSEDFwWahKzZ". If you want to use any other characters you have 
to use SimpleDateFormat.applyLocalizedPattern(String).                  
So: SimpleDateFormat("uuuu", Locale.GERMAN); will thow                  
IllegalArgumentException, but format = SimpleDateFormat("",             
Locale.GERMAN); followed by format.applyLocalizedPattern("uuuu"); is OK.
                                                                        
As I mentioned in the PMR this was reported to Sun in sunbug 4265184    
which the closed as "Will Not Fix" - I suspect the reason Sun will not  
fix this is that if they change the code to work the way that might seem
more intuitive then any pre-compiled code that uses the existing        
behaviour will fail and Sun are very hot on backwards compatibility.    
                                                                        
Either the strings in the translated property page need changing to     
valid characters or the code needs changing to use                      
allpyLocalizedPattern(). If the code and property page are both owned by
eclipse then this is indeed an eclipse bug.    
**********************
Comment 5 Oleg Besedin CLA 2009-12-21 09:54:46 EST
There seems to be two problems in the bundle "org.eclipse.ltk.ui.refactoring":

1) The code above throws an exception when invalid input data is encountered. I would expect it to produce a error in the error log and fallback to some "default" state.

2) Aparently German translation of the file org.eclipse.ltk.ui.refactoring\src\org\eclipse\ltk\internal\ui\refactoring\RefactoringUIMessages.properties

is incorrect for several entries. Assuming you are using Babel-provided translation, anybody with a Bugzilla account can modify those:

http://babel.eclipse.org/babel/translate.php
Comment 6 Markus Keller CLA 2010-01-05 05:34:26 EST
These localPatternChars only complicate translation, are not documented, contain errors, and should not be used any more, see e.g. advice at end of
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6289803
They even have been changed in the past (e.g. JDK 1.4 had different symbols for "de_CH" and "de", but in JavaSE 5.0, "de" uses the same symbols as "de_CH").

This snippet returns the (undocumented) localPatternChars:
    new java.text.DateFormatSymbols(
            new java.util.Locale("en", "US", "")).getLocalPatternChars()

I think the best solution for the future is to stop NLSing these patterns and just render the dates in the user's locale. That's how we do this everywhere else (e.g. resource properties, CVS history, etc.). Furthermore, nobody seems to care too much about this, since the current implementation of RefactoringHistoryLabelProvider is already buggy (uses the NLS'd locale in some places but not everywhere), and nobody complained.

Unless anybody objects, I'll do that for 3.6 M5.


Franka, do you also need a solution for this for older versions? The snippet above can be used to find the localized localPatternChars, and this information can be used to fix the translations in older builds. Could you do these updates in Babel? E.g. here:
http://babel.eclipse.org/babel/translate.php?project=eclipse&version=3.5&file=org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIMessages.properties&string=RefactoringHistoryLabelProvider_this_month_format


(In reply to comment #5)
> 1) The code above throws an exception when invalid input data is encountered.
No, that's not input data. We never protect against bugs in translation files.
Comment 7 frankar CLA 2010-01-06 19:41:50 EST
Markus - both the last 2 version of RD/z are running on 3.4.2 eclipse. A fix in 3.6  is not good for my German customers.
Comment 8 Markus Keller CLA 2010-01-07 08:49:33 EST
(In reply to comment #6)
Darn, I forgot about ICU. Since 3.8, ICU does *not* use localized localPatternChars any more, but always uses the default (en_US) ones. So the solution for most usages of LTK is to make sure that the patterns in
RefactoringHistoryLabelProvider_*_format entries are simply not touched in translations. I'll do that in Babel for 3.4 and 3.5 in all languages.

The only remaining problem is that the com.ibm.icu bundle can be replaced by com.ibm.icu.base, which is a shallow version that just forwards everything to the corresponding Java APIs from the JRE. That case will fail when all the translations contain the localPatternChars from en_US, but this is a rare setup that should not occur in products that are being localized.

In 3.6, I'll
(1) clarify the comment in RefactoringUIMessages.properties
(2) make sure in code that the default localPatternChars are used also when ICU has been replaced by com.ibm.icu.base
Comment 9 Markus Keller CLA 2010-01-13 09:32:09 EST
Created attachment 155976 [details]
Fix for HEAD

Fixed in HEAD (for 3.6). Removed all the locale-specific code and added this comment in RefactoringUIMessages.properties:

## These properties are date format patterns for the en_US locale, as defined in DateFormatSymbols.
## Do *not* localize the characters. If necessary, you can change the repetition count or the order of tokens.
Comment 10 Markus Keller CLA 2010-01-13 09:43:33 EST
Filed http://bugs.icu-project.org/trac/ticket/7328 for a bug in ICU's documentation for SimpleDateFormat pattern "MMMMM". I've fixed our code to use "MMMM" in HEAD, but the ICU Javadoc is still broken.
Comment 11 Markus Keller CLA 2010-01-20 11:11:11 EST
We're done for 3.6.

Keeping the bug open as a reminder to fix entries in Babel (which can only be done correctly after bug 299049 has been fixed).
Comment 12 Markus Keller CLA 2010-02-02 08:50:30 EST
For 3.4.x and 3.5.x, the fix is to fix ...
/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/internal/ui/refactoring/RefactoringUIMessages.properties
... in the affected translation packs:


* These properties should match the locale of the language pack, leaving non-applicable properties empty.
E.g. for German, use "language=de", "country=", and "variant=", or
for Portuguese (Brazilian), use "language=pt", "country=BR", and "variant=":

RefactoringHistoryLabelProvider_label_language=en
RefactoringHistoryLabelProvider_label_country=US
RefactoringHistoryLabelProvider_label_variant=


* These properties should stay exactly like this (i.e. don't try to translate the letters):

RefactoringHistoryLabelProvider_this_week_format=w
RefactoringHistoryLabelProvider_last_week_format=w
RefactoringHistoryLabelProvider_this_month_format=MMMMM yyyy
RefactoringHistoryLabelProvider_last_month_format=MMMMM yyyy
RefactoringHistoryLabelProvider_week_format=w
RefactoringHistoryLabelProvider_year_format=yyyy
RefactoringHistoryLabelProvider_month_format=MMMMM
RefactoringHistoryLabelProvider_day_format=EEEE
Comment 13 Markus Keller CLA 2010-02-08 13:44:12 EST
Fixed in Babel N20100209-0400 for all languages in 3.3.1, 3.4, and 3.5.