JDeveloper 11g R1: Advanced Multi Column Table Sort

A question on the JDeveloper and ADF Community Space found my attention. A user asked how to sort an af:table after more then one column.
Well, there is the official way, which Frank Nimphius’s bloged about in ‘Declarative multi-column sort for ADF bound tables’.
However this declarative approach needs the user to select the columns and their sort order. In most cases the sort after a second column is driven by the use case specification. A sample would be that the departments tables should normally be sorted after the column selected by the user, but then the data should always be sorted by the department name inside the first sort.
The image below shows the Departments table sorted first after the LocationId and inside the LocationId sorted by the DepartmentName.

Departments sorted after LocationID and DepartmentName

Departments sorted after LocationID and DepartmentName

Now lets see how to implement this. There are some possible solutions:

  1. add a sort criterion in a managed bean
  2. add a sort Criterion in the ViewObject
  3. a combination of 1) and 2)

All solutions have their advantages and disadvantages. Let’s start with the managed bean approach. This is pretty simple as we only need to add sortListener to the af:table which is pointing a bean method. In the sample below we are using the departments table where we wire up the secondary sort to the DepartmentName column.

<af:table value="#{bindings.DepartmentsView.collectionModel}" var="row" rows="#{bindings.DepartmentsView.rangeSize}"

And the sortTableListener in the bean

    public void sortTableListener(SortEvent sortEvent) {
        //log the selected column (just for information)
        List<SortCriterion> criteria = sortEvent.getSortCriteria();
        for (SortCriterion sc : criteria) {
            logger.info("Sort after: " + sc.getProperty());
        // Create new SortCriterion for DepartmentName in ascending order
        SortCriterion scNew = new SortCriterion("DepartmentName", true);
        // Add it to the list
        // and apply it back to the table
        Object object = sortEvent.getSource();
        RichTable table = (RichTable) object;

That’s all we need to do to get the output from the first image. You’ll notice, that both columns are showing the sort icon. Only the one for the DepartmentName can’t change to descending order as we wired things up to always sort in ascending order. From the users point of view this can be disturbing as it’s not obvious why this happens.

For the second solution we use the model layer instead of the view layer. Here we implement the ViewObjectImpl class of the EmployeesView and overwrite the setOrderByOrSortBy(…) method. This is the method the framework calls when you click on a header on the table to sort it.
Now we can hard wire the secondary sort column, as we did in the managed bean. However, let’s think about how to make this more flexible. A nice add on is that we can use the custom properties of each table attribute to define the secondary sort column. This way we can decide which columns to sort after for each of the attributes available. We can even decide to add more then one column for secondary and third sort.

The overwritten setOrderByOrSortBy method looks for the custom property named ‘SECONDARY_SORT’ and if found, creates a new SortCriterion with the column name give in the custom property. This new sort criterion is then added to the list of SortCriteria.

    public String setOrderByOrSortBy(SortCriteria[] sortCriteria) {
        SortCriteriaImpl scNew = null;
        // iterate current sort criteria
        for (int i = 0; i < sortCriteria.length; i++) {
            logger.info("Sort: " + sortCriteria[i].getAttributeName());
            // check for SECONDARY_SORT propertie on each attribute
            int attributeIndexOf = this.getAttributeIndexOf(sortCriteria[i].getAttributeName());
            AttributeDef attributeDef = this.getAttributeDef(attributeIndexOf);
            Object object = attributeDef.getProperty("SECONDARY_SORT");
            if (object != null) {
                logger.info("Secondary sort:" + object.toString());
                scNew = new SortCriteriaImpl(object.toString(), false);

        if (scNew != null) {
            // Create a new array for the added criteria
            SortCriteria scNewArray[] = new SortCriteria[sortCriteria.length + 1];
            for (int j = 0; j < sortCriteria.length; j++) {
                scNewArray[j] = sortCriteria[j];

            // add the new criteria
            scNewArray[sortCriteria.length] = scNew;
            //and exceute the search
            return super.setOrderByOrSortBy(scNewArray);
        return super.setOrderByOrSortBy(sortCriteria);

The image blow shows the result for the employees table which is first sorted after the ManagerId and then after the FirstName of the employee.

Sort after ManagerId and LastName

Sort after ManagerId and LastName

As you see, only the ManagerId column shows the sort icon. The secondary sort column, FirstName, doesn’t show the sort icon.

You can download the sample application, which uses the HR DB schema from the ADF-EMG ADF Samples Repository: BlogAdvancedTableSort.zip

Free Event on ADF Mobile in Germany: ‘Going Mobile – auf Geschäftsanwendungen zugreifen – mit Oracle ADF Mobile’


English message follows!

Oracle hält einen kostenlosen 1 Tages Hands on Workshop zum Thema “Going Mobile – auf Geschäftsanwendungen zugreifen – mit Oracle ADF Mobile” in Frankfurt-Dreieich ab. Dies ist sicher interessant für alle ADF Mobile Entwickler, die auf dem neusten Stand der Technik bleiben Wollen. Meldet Euch an, die Teilnehmerzahl ist begrenzt.
Weitere Informationen findet man unter den im Quote angegebenen Links.

START English Message
Oracle holds a free ADF Mobile 1 day Hands-On workshop in Frankfurt, Germany on 2nd, June 2014. If you like to learn about ‘Going Mobile – auf Geschäftsanwendungen zugreifen – mit Oracle ADF Mobile‘ the event is for you. Please register as soon as possible as the number of attendees is restricted.

The event is held in German language!
END English Message

Going Mobile – auf Geschäftsanwendungen zugreifen – mit Oracle ADF Mobile – 1 Tages Hands on Workshop
Immer häufiger gibt es die Anforderungen aus den Fachabteilungen wie Vertrieb oder Logistik, auch vom Tablet oder Smartphone auf existierende Anwendungen wie CRM oder ERP zugreifen zu wollen.
Mittels Oracle ADF Mobile können Sie dies schnell umsetzen. Entwickler mit Java oder ADF Kentnissen können ihr Wissen sofort einbringen.
Aber auch Entwickler ohne Programmierkenntnisse können Oracle Mobile sofort produktiv nutzen.
In diesem Hands-On Workshop erlernen Sie das Basiswissen zum Umgang mit den Oracle Technologien Oracle ADF Mobile sowie dem JDeveloper und Weblogic Server. Sie werden im Workshop eine mobile Anwendung entwickeln und auf Ihrem Smartphone oder Tablet (Android, iOS) ablauffähig installieren.
Mehr zu Oracle Mobile auf dieser Seite.

Zeit: 2. Juli 2014 – Beginn 10:00h – Ende: 17:00h
Ort der Veranstaltung:
Oracle Deutschland B.V. & Co KG
Robert-Bosch-Straße 5
63303 Dreieich
Anmeldelink hier. Die Teilnahme ist kostenlos. Die Teilnehmerzahl ist begrenzt.
Systemvoraussetzungen für den Workshop finden Sie hier.

Using one ViewObject for Global Lookup Data (Part 3): Multi Language Support

In an earlier post I blogged about a how to use a DB table to hold look up data like gender, weekdays or title which can used in different locations as ‘List Of Value’ data (Using one ViewObject for Global Lookup Data (Part 2)).
This third part adds a use case where we add multi language support when we read data from the DB table. This is an enhancement of the use case implemented in part 2. The old use case could load data in one language only. Now we add the the language to the data in the db table to allow retrieval of language specific data.

To make the use case work, we add two columns to the existing table GENERALLOOKUP. The first one holds the language code and the second one an id which is unique in the type and language. We use this new id named ‘GROUPID’ in the LOV to show the data of the selected type.
The ‘GROUPID’ remains identical for each type and language so that we can enter data in different languages. For the language code we use the codes we get from a Locale class. A sample for the data of WEEKDAY Monday:

Sample for Multilanguage Entry

Sample for Multilanguage Entry

We start by changing the DB table GENERALLOOKUP we used in the sample introduced in part 2. The sql script setup_db_multilangual.sql which is part of the project workspace, adds the two mentioned columns. You find the link to download the workspace at the end of this post. The script holds the needed data for the multi language look up too.
The final DDL for the GENERALLOOKUP table is

    "ID" NUMBER, 
   ) ;

Next we synchronize the existing EO with the new GENERALLOOKUP table to get the new attributes into the EO

Synchronize with DB

Synchronize with DB

Here are some of the dialogs which you see when synchronizing the DB to the business objects

Now we have to add the new columns to the VO as well

These changes now allow to use the VO GeneralLookup to select language dependent look up data from the db. We now a new view criteria, named TypeLookupByLanguageViewCriteria, to use the language information to only select data for one language and one type from the table.

This new view Criteria uses two bind variables to select only data of one type and one language. How to set these variables we see later in this post.
As we don’t want to break the old application we create a new VO based again on the existing Lookuptest entity object and name it ‘LookupMultiLanguageView’

Next step is to set up the LOVs accessors for the attributes WeekdayId, GenderIs, PositionId and TitleID. Here we only show how to do this for the WeekdayId attribute. The images below showing that we not only set the bindType to ‘WEEKDAY’, but the bindLanguage variable too. Here we use a groovy expression to get the current language from the current locale

The real work is done in pictures 3, 4, 5 and 6 where we use the view criteria we’ve build earlier (TypeLookupByLanguageViewCriteria) to select the type and language from the GeneralLookupView.
In Image 3 we use the GenerallookupView as view accessor for the weekdayId. We rename the accessor to WeekdayMultiLanguageLOV for better understanding what the view accessor does. As the WeekdayMultiLanguageLOV can select any type in any language, we have to use the view criteria and set its bind variables to only get the data we want. In this case we set the bindType variable to ‘WEEKDAY’ and the bindLanguage variable to the current language used in the browser. As this language can change, we can’t use a static string like we used for the bindType. The language has to be calculated. For this we use a groovy expression:

oracle.adf.share.logging.ADFLogger LOGGER = oracle.adf.share.logging.ADFLogger.createADFLogger(source.getClass()); 
loc = adf.context.locale; 
if (loc == null) {
  LOGGER.info("Language not set -> en");
  return 'en';
} else {
  lang = loc.language;
  shortLang = lang.substring(0,2);
  if (!"#de#it#fr#en#".contains(shortLang)) {
    LOGGER.info("Language not recognized -> en");
  } else {
    LOGGER.info("Language set to -> "+lang.substring(0,2));
    shortLang = lang.substring(0,2);

Yes, you can do more with groovy then just simple calculations like “sal *12″!
We use groovy expression like a java function to get the locale from the AdfContext (groovy: loc = adf.context.locale;) and from the locale we get the language (groovy: lang = loc.language;). Now, there are some checks to make, like is the locale is set and if the language found is one of the languages we support. In this sample we only support ‘en’, ‘de’, ‘it’ and ‘fr’ but you can add other languages too. As the language we get from the locale can look like ‘en_US’ or ‘de_CH’ we only use the first two characters (groovy: shortLang = lang.substring(0,2);). You can even use a logger to print out information into the log.

We can now test the switching of languages in the application module tester. Before we start the tester we make sure we can change the locale in the tester. Open the menu ‘Tools’->’Preferences’ and select the node ‘Business Components’, then select the ‘Tester’ node where you can add different languages for the tester.

Supply Languages to Tester

Supply Languages to Tester

Running the tester

Please notice the log output which is visible below the tester which shows the groovy log messages.

Finally we adjust the UI by adding a new page MultiLanguageLookup and hook it up with the existing LookupTest page.

Setup New Test Page

Setup New Test Page

Then we need to setup the faces-config.xml to support multiple languages
Setup New Test Page

Setup New Test Page

Now, if we run the application and change the browser language, reload the page we see the language change

The sample used in this blog can be downloaded from the ADF-EMG Sample repository. The sample uses JDeveloper and the HR DB schema.

JDev and IE11 Patches are finally available for all ‘current’ versions


[UPDATE 2014-03-07] added correct patch number for JDev

Since February 25th 2014 the missing patch for JDev to make ADF application work with IE11 has arrived. In OTN forum thread https://community.oracle.com/thread/2624119 you find the details of the delay.
The patch for has Id 18091042
The patches for the other versions are mentioned in doc ID 1599898.1. The document itself is a bit outdated as the patch for JDev 12.1.2 is missing in the doc.
Here is the summary of the available patches:

    patch 17236592 – IE11 SUPPORT: ADF APPS DON’T LOAD WITH IE11
    patch 18071063 – MERGE REQUEST ON TOP OF FOR BUGS 17236592 17672146 17723555 17723794
    patch 17236592 – IE11 SUPPORT: ADF APPS DON’T LOAD WITH IE11
    Fix also included in patch 18071063.
    Patch 18277436: MERGE REQUEST ON TOP OF FOR BUGS 18070879 18176711
    patch 18091042 – MERGE REQUEST ON TOP OF FOR BUGS 17236592 17663878 17672146 17723555

Good News: ADF and IE11 working together again


Yesterday (Jan 15th, 2014) Oracle support came up with a patch for JDeveloper in concern of running ADF applications using IE11.
Form Article Id 1599898.1:

Below is a list with available patches for IE11 issues. The list will be updated once more patches become available. However this does NOT mean IE11 is certified but the patches allows you to access the application IE11:

patch 17236592 – IE11 SUPPORT: ADF APPS DON’T LOAD WITH IE11
Patch to avoid the popup shown above from appearing.

You need a support contract to get the patch.

End of Year 2013 – What’s coming up 2014


The year 2013 is fast approaching its end. It was an extremely busy year for me, a couple of new projects needed my attention, other projects were finished (successful :)).

The German ADF Community (https://www.xing.com/net/adfcomm or https://twitter.com/ADFCommunityDE) opened from a partner community to everybody interested in sharing experience using ADF in all kind of projects. We had a well visited Hackers Event in January, the one day DOAG 2013 Development event in June, and the DOAG Conference in November and not to mention the ADF News Session, which are now called ADF Spot Light Sessions.

In Germany the ADF Community is growing and we are getting more and more interesting content and discussions. The ADF-EMG also gets more attention. Jack Flack is the new group moderator and doing his job very well, good luck John. We have to thank Chris Muir who did a great job as moderator of the ADF-EMG group.
The ADF G+ group Oracle JDeveloper, ADF & ADF Mobile was introduced late 2012 and has currently 982 (time of writing) members! Very impressive!
New members are welcome!

On the JDeveloper front we finally got the long awaited 12c version. It’s still not the big new version which has all parts (Mobile, SOA, BPM, …) in one IDE, but this will hopefully come soon. From the number of bugs found in the version it’s not too bad that we have to wait for the as this version has some of the nasty bugs fixed (https://java.net/jira/browse/ADFEMG).

So, what is to expect 2014?

The DOAG and the German ADF Community cater an ADF Bar Camp directly followed by an ADF Fitness Center.
The one day DOAG 2014 Development will be in Düsseldorf this year, a new attractive location which can easily be reached.

Do we see a new ADF Mobile version? New SOA? New BPM? New JDeveloper?
I think so, can’t be too long…

A final note on the OTN JDeveloper and ADF Forum:
I don’t know what Oracle is doing here. A big multinational corporation is not capable to come up with a working forum software. We all knew the old software could not be changed and had its bugs and breakdowns.
However, after installing the new software it we soon learned: new doesn’t mean better!
The users of the forum, or ‘space’ as it’s called nowadays, don’t get any information until they have found out themselves. No official statement (most of the time) on the things which have changes. This reminds me on the projects I participated which went very very wrong.
I hope Larry E. decides that not only the US Health Care needs help (is their web page running?), but the forum needs help from his best consultants too.

Wish you all a great and happy new year 2014!

DOAG 2013


I’m on my way to #DOAG2013 in Nürnberg, Germany, right now and have time to write this short blog about the next couple of days at DOAG in Nürnberg.

The final touches on the demos for my sessions are done :)

If you are attending #DOAG2013 please visit my session about using dynamic pivot tables on Tuesday, 19th, 10 am and my other session on implementing a big application using the pillar architecture on Tuesday, 19th, 3 pm.

In the meantime you may want to visit the German ADF Community also Tuesday 19th 2pm right on the #DOAG2013 ground. To make the day a real productive one finish with attending the Forms and ADF Expert Panel Tuesday, 19th, 5pm. Here you can gather useful information and ask questions directly to experts (and product managers which I assume are experts).

Wednesday is the day of ADF Mobile, at least for me. Let’s see how ADF Mobile has developed since last year. I couldn’t spend time to look into mobile development deeply. Hope that I have a chance this year. DOAG is the right way to gather information and get up to speed with mobile development.

The third and final day i’ve not decided, but it looks like room hopping to get some sessions on SOA, BI and other middleware stuff.

Empty Test for String Values using Expression Language

On the OTN ADF & JDeveloper space (aka forum) I often read use cases where an action depends on the state of an af:inputText, or better the value entered in the component.
This is problematic as a String value can either be null or it can be empty. The problem is that is you want to test a String value using Expression Language (EL) in the UI, you can’t use e.g.

#{bindings.myText1.inputValue eq ''}

The solution is an existing, but mostly unknown operator of Expression Language (EL) called ‘empty’. This operator checks a String value if it’s empty. Usage of the operator is a bit different from the other operators which are used after the value. The ‘empty’ operator is used in front of the valeu like

#{empty bindings.myText1.inputValue}

consider the following use case: a button should be enabled only if a inputText component is not empty. For this we can use this code

            <af:panelGroupLayout layout="scroll" xmlns:af="http://xmlns.oracle.com/adf/faces/rich" id="pgl1">
              <af:inputText label="Label 1" id="it1" value="#{bindings.myText1.inputValue}" autoSubmit="true"/>
              <af:commandButton text="commandButton 1" id="cb1" disabled="#{empty bindings.myText1.inputValue}" partialTriggers="it1"/>
              <af:outputText value="Working (empty bindings.myText1.inputValue): #{empty bindings.myText1.inputValue} --- not working(bindings.myText1.inputValue eq '': #{bindings.myText1.inputValue eq ''}" id="ot1"

As you see, the af:inputText component stored it’s value in a pageDef variable (or a VO row) and submits the entered value using the autoSubmit property set to ‘true’. The af:commandButton gets enabled only if the EL
#{empty bindings.myText1.inputValue}
returns false. This is the case when you enter anything into the af:inputText. The final piece to make it work is the partial trigger on the af:button component listening to the change of the input value.
The outputText below the button is just to show that the EL
#{bindings.myText1.inputValue eq ''}
does not work correctly.

JDev 12c: How to reset a filter on an af:table the 12c way

This post is a continuation of an earlier blog about how to reset a filter on an af:table.
A question on OTN JDev and ADF spaces brought a change to my attention which I like to share here.
Using the code from the former post now results in a depreated warning in 12c:

    public void resetTableFilter(ActionEvent actionEvent)
        FilterableQueryDescriptor queryDescriptor =
            (FilterableQueryDescriptor) getEmpTable().getFilterModel();
        if (queryDescriptor != null && queryDescriptor.getFilterCriteria() != null)
            getEmpTable().queueEvent(new QueryEvent(getEmpTable(), queryDescriptor));

Warning(7,28): getFilterCriteria() in oracle.adf.view.rich.model.FilterableQueryDescriptor has been deprecated

and a look into the javadoc for the getFilterCriteria() method showed

Deprecated. Please use #getFilterConjunctionCriterion

AFAIK you only get the javadoc if you have access to the source code of ADF which you can get via support.oracle.com.

Knowing what to use instead of the deprecated method is half the solution. It turned out that it’s not enough to to use the new method to get the FilterConjunctionCriterion but that you have to iterate over the ConjunctionCriterion and reset them one by one. Here you have to check which type of ConjunctionCriterion you get from the iterator as there are two

  1. AttributeCriterion
  2. ConjunctionCriterion

Only the AttributeCriterion needs to be reset, the ConjunctionCriterion represents a group of AttributeCriterion.
The final code looks like:

     * method to reset filter attributes on an af:table
     * @param actionEvent event which triggers the method
    public void resetTableFilter(ActionEvent actionEvent) {
        FilterableQueryDescriptor queryDescriptor = (FilterableQueryDescriptor) getEmpTable().getFilterModel();
        if (queryDescriptor != null && queryDescriptor.getFilterConjunctionCriterion() != null) {
            ConjunctionCriterion cc = queryDescriptor.getFilterConjunctionCriterion();
            List<Criterion> lc = cc.getCriterionList();
            for (Criterion c : lc) {
                if (c instanceof AttributeCriterion) {
                    AttributeCriterion ac = (AttributeCriterion) c;
            getEmpTable().queueEvent(new QueryEvent(getEmpTable(), queryDescriptor));

The rest of the implementation remained unchanged so you only need exchange the resetTableFilter method in ResetTableFilterBean.java.
The sample used the HR schema as DB connection. You can download the sample workspace for JDev12c from the ADF-EMG Sample Repository.

JDeveloper 12c: New or Changed Features

Over the last couple of days I took some time to check out some of the new features and changes in the UI of the new JDeveloper version (aka JDev12c). My other post on this issue already mentioned some features.
This new post adds some more:

UI & Handling
In my post Creating Variables and Attribute Bindings to Store Values Temporarily in the PageDef I showed how to setup page variables using the ‘variables’ iterator of the pageDef. There have been some change to the UI so that you can’t insert new variables via the pageDef editor (as it was in 11g). Variables are now added via the structure window only. I’m not sure if this is a bug or feature.

Completion Insight
This is the feature you use to get help in the editor window when you hit ‘ctrl-space’ on Java code or a jsf tag. It shows you which methods (for java) or which properties (for tags) are available. You can open a ‘Documentation’ window which should get you the e.g. javadoc. It looks like this functionality does not work for ADF or Trinidad components at the moment.

Completion Inside broken

Completion Inside broken

For default java methods you get help as in earlier version

Completion Inside working

Completion Inside working

Javadoc comes in a new, more modern design. Just put your cursor on some java code (e.g. String) and hit F1:
Blog12cfeatures 005

Javadoc in new Design

Javadoc in new Design

Compile and Rebuild
A new useful addition to the compilers errors and warnings are the ‘Live Issues’ in a tab you get when you compile or rebuild a project or class. This new tab allows you to quickly check audit rules and fix minor issues directly.

Live Issues

Live Issues

Another long waited for feature is the direct compile option which can be switched on in the preferences for the compiler settings (two last check boxes in the image below):

Compile After Save Option

Compile After Save Option

Activating this option will recompile all changes after you save them. If you change a page and save the changes (e.g. you add a detail item and add a table on it) you’ll get

<18.07.2013 17:27 Uhr MESZ> <Warning> <Socket> <BEA-000449> <Closing the socket, as no data read from it on during the configured idle timeout of 5 seconds.> 
[05:50:33 PM] Updated /P:/jdeveloper/system/system12.

but the added showDetailItem will not be able to retrieve the data. Instead you get an ‘Access denied’ message.

Saving is not enough

Saving is not enough

Clicking on ‘Compile’ to make it work you have to recompile it again to get

<18.07.2013 18:02 Uhr MESZ> <Warning> <Socket> <BEA-000449> <Closing the socket, as no data read from it on during the configured idle timeout of 5 seconds.> 
[06:03:08 PM] Updated /P:/jdeveloper/system/system12.

Now you should be able to retrieve the data too. Look like hot deployment is working!

Running Application after Recompile

Running Application after Recompile

Debugging an Application
When you debug an application you normally end up with lots of breakpoints in different files. This is OK until you localized the cause of an error you are debugging. However, once you have found it you like to resume normal work without hitting all the breakpoints set earlier. For this the debug button bar has a new button to disable all breakpoints with one click:

Blog12cfeatures 010

Breakpoint Toggle

Breakpoint Toggle

Edit Jsf Page
Not sure what we see here, but it looks like a quick way to edit labels of components. As long as the label property of a component is empty or shows an EL you get this little window where you can select a text resource, enter an EL or enter static text. Once you have static text in the property you don’t get the window until you remove the static text.

Label Quick Selector

Label Quick Selector

Dependency Explorer
The Dependency Explorer allows you to quickly find where a component is used and how. This feature can be used e.g. to find out where a fragment is used.
Sample: you have a fragment open in the editor and like to know where this fragment is used in the project. Use menu ‘Search->Explore Dependency’ and you get a nice graphical display like:

Dependency Graph

Dependency Graph

Clicking on the numbers show you how the artifact is used (e.g. as taskflow call in another page)

How is the artifact used

How is the artifact used

True Mode
The design view now allows a quick switch into the so called ‘True Mode’. This display mode hides all visual help you normally get when you create a page or fragment. A visual help are e.g. the name and size of facets (e.g. of a panelStretchLayout). Turning this off give you a better feeling how the resulting page will look like in the browser.

Design Mode

Design Mode

True Mode

True Mode

File Templates
The ‘What’s New’ document mentiones ‘File Templates’ as

File Templates: Define custom file templates and invoke them from the gallery.

You’ll find them in the Preferences under ‘File Templates’, but I couldn’t find any documentation about how to use them.
If someone knows how to use them, drop me a note, please.

This concludes the findings on new or changes on JDev12c for now. I’m sure there are many more useful gem hidden and waiting to be discoverd.