Categories
Java

MojoFailureException: Fix Maven’s Compilation Failure:

Today, I faced a compilation failure in Bitbucket pipelines for a simple Java project. The project compiles successfully in the local machine.

The stack trace of the failure was not useful at all:

------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  9.655 s
[INFO] Finished at: 2020-10-14T22:24:42Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:testCompile (default-cli) on project automation: Compilation failure -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:testCompile (default-cli) on project automation: Compilation failure
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:215)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:566)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
Caused by: org.apache.maven.plugin.compiler.CompilationFailureException: Compilation failure
    at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute (AbstractCompilerMojo.java:1224)
    at org.apache.maven.plugin.compiler.TestCompilerMojo.execute (TestCompilerMojo.java:180)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo (DefaultBuildPluginManager.java:137)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:210)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:156)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute (MojoExecutor.java:148)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:117)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject (LifecycleModuleBuilder.java:81)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build (SingleThreadedBuilder.java:56)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute (LifecycleStarter.java:128)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:305)
    at org.apache.maven.DefaultMaven.doExecute (DefaultMaven.java:192)
    at org.apache.maven.DefaultMaven.execute (DefaultMaven.java:105)
    at org.apache.maven.cli.MavenCli.execute (MavenCli.java:957)
    at org.apache.maven.cli.MavenCli.doMain (MavenCli.java:289)
    at org.apache.maven.cli.MavenCli.main (MavenCli.java:193)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:566)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced (Launcher.java:282)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch (Launcher.java:225)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode (Launcher.java:406)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main (Launcher.java:347)
[ERROR] 
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

The stack trace doesn’t report any file names or lines numbers. This means the compilation error is not with the source code itself.

Reading the help doc gave me some clue about the problem. After spending some time in investigation, I found that this issue occurred because I was using a custom executable for maven-compiler-plugin that includes a environment variable:

<plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>11</source>
          <target>11</target>
          <executable>${env.JAVA_11_HOME}/bin/javac</executable>
          <fork>true</fork>
        </configuration>
</plugin>

Since this environment variable was present in my local system but was not set in Bitbucket pipelines, I was getting the above exception. Setting the environment variable like below in my bitbucket-pipelines.yml file resolved the issue:

image: maven:3.6.3-openjdk-11
pipelines:
  default:
    - step:
        script:
          - JAVA_11_HOME=/usr/local/openjdk-11 mvn -e -X clean compile compiler:testCompile
Categories
IntelliJ MySQL

IntelliJ – Connect to MySQL running in Vagrant

The Database feature of IntelliJ/PHPStorm is very powerful compared to the MySQL CLI. It allows your edit your data from the UI easily without writing any MySQL commands.

Here is how you can connect your MySQL server running in a vagrant machine to the IntelliJ’s database feature and improve your productivity during development.

Create a new MySQL Data Source with these basic configuration:

Fill the basic details such as the data source name, host, port, user name, password and the database name.

Make sure you add ?useSSL=false to the JDBC URL after the form is filled. MySQL 5.7+ has SSL enabled by default.

Full JDBC url: jdbc:mysql://localhost:3306/development_database?useSSL=false

Now, with this default configuration, the connection will not work because we need to set the SSH configuration to allow IntelliJ to talk to the MySQL server running within the vagrant VM.

Goto the SSH/SSL tab, select ‘Use SSH tunnel’ and fill-in the details like this:

The value for Private key file should be the one from IdentityFile from your project vagrant directory using this command:

~/Dropbox/Projects/myproject
❯ vagrant ssh-config
Host default
  HostName 127.0.0.1
  User vagrant
  Port 2222
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/lrajasekaran/Dropbox/Projects/myproject/.vagrant/machines/default/virtualbox/private_key/private_key
  IdentitiesOnly yes
  LogLevel FATAL

Now click ‘Test Connection’ from this dialog to ensure the SSH connection is working as expected. Once the SSH connection is setup, close this dialog, go to ‘General’ tab and click ‘Test Connection’ to test the actual database connection using the SSH connection made previously. Once this successful, goto ‘Schemas’ tab and select your database name and click ‘Apply’.

Now you can view all your tables from the Database tool window on the right. Right click on any table and click ‘Jump to Editor’ to see the table rows:

Any value can be edited directly from this UI and then saved to the DB by right clicking the row and clicking ‘Submit’

Categories
React

React – Render String with HTML tags as HTML

TRY IT LIVE

Click the button below to see a live example of this example that you can edit and try for yourself.

CODE SANDBOX

There are often times when you have a string with some HTML tags such as strong that you want to render as HTML on the DOM. Most solutions online recommend using dangerouslySetInnerHTML but that is dangerous as the name suggests. The proper way to render HTML from string is to use FormattedMessage from the formatjs library (react-intl version 5).

Here is a code example:

import React from "react";
import "./styles.css";
import { IntlProvider, FormattedMessage } from "react-intl";

export default function App() {
  return (
    <IntlProvider>
      <div className="App" style={{fontSize: 24}}>
        <FormattedMessage
          id="app.greeting"
          description="Bold text example"
          defaultMessage="Look here, I can include HTML tags in plain string and render them as HTML: <b>Bold</b>, <i>Italics</i> and <a>links too</a>."
          values={{
            b: (chunks) => <b>{chunks}</b>,
            i: (chunks) => <i>{chunks}</i>,
            a: (chunks) => (
              <a class="external_link" target="_blank" href="https://jiga.dev/">
                {chunks}
              </a>
            )
          }}
        />
      </div>
    </IntlProvider>
  );
}

This should show an output as:

Play with code sample in this link: https://codesandbox.io/s/react-render-html-from-props-string-c9ogm

You can also pass the defaultMessage and values as prop values from other components.

In the above example, I have used the version 5 from the react-intl library. In the previous versions, the API is a little different. Follow the official documentation for more options such as using child elements.

Categories
PHP

Debug slow PHP applications using IntelliJ or PHPStorm

It is frustrating when your PHP application is really slow and you do not know which part of your code is taking up too much time.

Google considers 2 seconds as the optimal loading time for a fast loading website.

Enabling PHP XDebug Profiler

PHP’s Xdebug extension can be used to profile your web requests and CLI requests and understand why they are slow and which method is causing the bottleneck.

Follow this link to install XDebug on the server on which your PHP application is running: https://xdebug.org/docs/install

Once XDebug is installed successfully, open the xdebug configuration file and add the following line:

xdebug.profiler_enable = 1

Once you add the above line, the configuration file should look like this:

vagrant@dev:/etc/php/7.2/cli/conf.d$ cat 20-xdebug.ini
zend_extension=xdebug.so
xdebug.show_error_trace = 1
xdebug.profiler_enable = 1

The above file only enables the profile for CLI requests. For enabling the profile for web requests, add the same line into the following file:

vagrant@dev:/etc/php/7.2/fpm/conf.d$ cat 20-xdebug.ini
zend_extension=xdebug.so
xdebug.show_error_trace = 1
xdebug.profiler_enable = 1

Once the files are saved, restart the PHP FPM service:

service php7.2-fpm restart

Now you can open your phpinfo file and verify if the profiler is now enabled:

Generating the profile file

You can now open the slow webpage and PHP XDebug will create a profiler in the profiler_output_dir mentioned above (i.e. ./tmp) which can also be customized in the xdebug ini file.

I opened the homepage of my PHP application and found these files in my /tmp directory:

root@dev:/tmp# ls cache* -gGltrh
-rw-r--r-- 1 1.6K Sep 23 10:29 cachegrind.out.3315.01c00e
-rw-r--r-- 1 1.2M Sep 23 10:29 cachegrind.out.3315
-rw-r--r-- 1 2.1M Sep 23 10:31 cachegrind.out.3312
-rw-r--r-- 1 1.8K Sep 23 10:31 cachegrind.out.3312.0df7d7
-rw-r--r-- 1 1.2M Sep 23 10:31 cachegrind.out.3315.05bc8d
-rw-r--r-- 1 1.2M Sep 23 10:31 cachegrind.out.3312.073921
-rw-r--r-- 1 2.0K Sep 23 10:31 cachegrind.out.3312.03dc36

Analyzing the generated files

Once these files are generated, you can open them in IntelliJ or PHPStorm for analysis:

Once you have finished the analysis, make sure to remove or comment the line xdebug.profiler_enable in both your ini files and restart your FPM service. Otherwise the tmp directory will get filled very quickly.

Other Free Tools

Apart from paid tools such as IntelliJ/PHPStorm, there are some free tools to analyze the generated cachegrind files:

Categories
Database MySQL

5 Reasons MySQL Foreign Key constraints fail to create

Finding out why Foreign key creation fail

When MySQL is unable to create a Foreign Key, it throws out this generic error message:

ERROR 1215 (HY000): Cannot add foreign key constraint

– The most useful error message ever.

Fortunately, MySQL has this useful command that can give the actual reason about why it could not create the Foreign Key.

mysql> SHOW ENGINE INNODB STATUS;

That will print out lots of output but the part we are interested in is under the heading ‘LATEST FOREIGN KEY ERROR’:

------------------------
LATEST FOREIGN KEY ERROR
------------------------
2020-08-29 13:40:56 0x7f3cb452e700 Error in foreign key constraint of table test_database/my_table:
there is no index in referenced table which would contain
the columns as the first columns, or the data types in the
referenced table do not match the ones in table. Constraint:
,
CONSTRAINT idx_name FOREIGN KEY (employee_id) REFERENCES employees (id)
The index in the foreign key in table is idx_name
Please refer to http://dev.mysql.com/doc/refman/5.7/en/innodb-foreign-key-constraints.html for correct foreign key definition.

This output could give you some clue about the actual reason why MySQL could not create your Foreign Key

Reason #1 – Missing unique index on the referenced table

This is probably the most common reason why MySQL won’t create your Foreign Key constraint. Let’s look at an example with a new database and new tables:

In the all below examples, we’ll use a simple ‘Employee to Department” relationship:

mysql> CREATE DATABASE foreign_key_1;
Query OK, 1 row affected (0.00 sec)
mysql> USE foreign_key_1;
Database changed

mysql> CREATE TABLE employees(
    ->     id int,
    ->     name varchar(20),
    ->     department_id int
    -> );
Query OK, 0 rows affected (0.08 sec)

mysql> CREATE TABLE departments(
    ->     id int,
    ->     name varchar(20)
    -> );
Query OK, 0 rows affected (0.07 sec)

As you may have noticed, we have not created the table with PRIMARY KEY or unique indexes. Now let’s try to create Foreign Key constraint between employees.department_id column and departments.id column:

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
ERROR 1215 (HY000): Cannot add foreign key constraint

Let’s look at the detailed error:

mysql> SHOW ENGINE INNODB STATUS;
------------------------
LATEST FOREIGN KEY ERROR
------------------------
2020-08-31 09:25:13 0x7fddc805f700 Error in foreign key constraint of table foreign_key_1/#sql-5ed_49b:
FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id):
Cannot find an index in the referenced table where the
referenced columns appear as the first columns, or column types
in the table and the referenced table do not match for constraint.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
Please refer to http://dev.mysql.com/doc/refman/5.7/en/innodb-foreign-key-constraints.html for correct foreign key definition.

This is because we don’t have any unique index on the referenced table i.e. departments. We have two ways of fixing this:

Option 1: Primary Keys

Let’s fix this by adding a primary key departments.id

mysql> ALTER TABLE departments ADD PRIMARY KEY (id);
Query OK, 0 rows affected (0.20 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
Query OK, 0 rows affected (0.19 sec)
Records: 0  Duplicates: 0  Warnings: 0

Option 2: Unique Index

mysql> CREATE UNIQUE INDEX idx_department_id ON departments(id);
Query OK, 0 rows affected (0.13 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
Query OK, 0 rows affected (0.21 sec)
Records: 0  Duplicates: 0  Warnings: 0

Reason #2 – Different data types on the columns

MySQL requires the columns involved in the foreign key to be of the same data types.

mysql> CREATE DATABASE foreign_key_1;
Query OK, 1 row affected (0.00 sec)

mysql> USE foreign_key_1;
Database changed

mysql> CREATE TABLE employees(
    ->     id int,
    ->     name varchar(20),
    ->     department_id int,
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.06 sec)

mysql> CREATE TABLE departments(
    ->     id char(20),
    ->     name varchar(20),
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.07 sec)

You may have noticed that employees.department_id is int while departments.id is char(20). Let’s try to create a foreign key now:

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
ERROR 1215 (HY000): Cannot add foreign key constraint

Let’s fix the type of departments.id and try to create the foreign key again:

mysql> ALTER TABLE departments MODIFY id INT;
Query OK, 0 rows affected (0.18 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
Query OK, 0 rows affected (0.26 sec)
Records: 0  Duplicates: 0  Warnings: 0

It works now!

Reason #3 – Different collation/charset type on the table

This is a surprising reason and hard to find out. Let’s create two tables with different collation (or also called charset):

Let’s start from scratch to explain this scenario:

mysql> CREATE DATABASE foreign_key_1;                                                                                        Query OK, 1 row affected (0.00 sec)

mysql> USE foreign_key_1;                                                                                                    Database changed

mysql> CREATE TABLE employees(
    ->     id int,
    ->     name varchar(20),
    ->     department_id int,
    ->     PRIMARY KEY (id)
    -> ) ENGINE=InnoDB CHARACTER SET=utf8;
Query OK, 0 rows affected (0.06 sec)

mysql> CREATE TABLE departments(
    ->     id int,
    ->     name varchar(20),
    ->     PRIMARY KEY (id)
    -> ) ENGINE=InnoDB CHARACTER SET=latin1;
Query OK, 0 rows affected (0.08 sec)

You may notice that we are using a different character set (utf8 and latin1` for both these tables. Let’s try to create the foreign key:

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
ERROR 1215 (HY000): Cannot add foreign key constraint

It failed because of different character sets. Let’s fix that.

mysql> SET foreign_key_checks = 0; ALTER TABLE departments CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; SET foreign_key_checks = 1;
Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.18 sec)
Records: 0  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.00 sec)

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
Query OK, 0 rows affected (0.20 sec)
Records: 0  Duplicates: 0  Warnings: 0

If you have many tables with a different collation/character set, use this script to generate a list of commands to fix all tables at once:

mysql --database=your_database -B -N -e "SHOW TABLES" | awk '{print "SET foreign_key_checks = 0; ALTER TABLE", $1, "CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; SET foreign_key_checks = 1; "}'

Reason #4 – Different collation types on the columns

This is a rare reason, similar to reason #3 above but at a column level.

Let’s try to reproduce this from scratch:

mysql> CREATE DATABASE foreign_key_1;                                                                                        Query OK, 1 row affected (0.00 sec)

mysql> USE foreign_key_1;                                                                                                    Database changed

mysql> CREATE TABLE employees(
    ->     id int,
    ->     name varchar(20),
    ->     department_id char(26) CHARACTER SET utf8,
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.07 sec)

mysql> CREATE TABLE departments(
    ->     id char(26) CHARACTER SET latin1,
    ->     name varchar(20),
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.08 sec)

We are using a different character set for employees.department_id and departments.id (utf8 and latin1). Let’s check if the Foreign Key can be created:

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
ERROR 1215 (HY000): Cannot add foreign key constraint

Nope, as expected. Let’s fix that by changing the character set of departments.id to match with employees.department_id:

mysql> ALTER TABLE departments MODIFY id CHAR(26) CHARACTER SET utf8;
Query OK, 0 rows affected (0.20 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
Query OK, 0 rows affected (0.20 sec)
Records: 0  Duplicates: 0  Warnings: 0

It works now!

Reason #5 -Inconsistent data

This would be the most obvious reason. A foreign key is to ensure that your data remains consistent between the parent and the child table. So when you are creating the foreign key, the existing data is expected to be already consistent.

Let’s setup some inconsistent data to reproduce this problem:

mysql> CREATE DATABASE foreign_key_1;                                                                                        Query OK, 1 row affected (0.00 sec)

mysql> USE foreign_key_1;                                                                                                    Database changed

mysql> CREATE TABLE employees(
    ->     id int,
    ->     name varchar(20),
    ->     department_id int,
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.06 sec)

mysql> CREATE TABLE departments(
    ->     id int,
    ->     name varchar(20),
    ->     PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.08 sec)

Let’s insert a department_id in employees table that will not exist in departments.id:

mysql> INSERT INTO employees VALUES (1, 'Amber', 145);
Query OK, 1 row affected (0.01 sec)

Let’s create a foreign key now and see if it works:

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);

ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`foreign_key_1`.`#sql-5ed_49b`, CONSTRAINT `fk_department_id` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`))

This error message is atleast more useful. We can fix this in two ways. Either by adding the missing department in departments table or by deleting all the employees with the missing department. We’ll do the first option now:

mysql> INSERT INTO departments VALUES (145, 'HR');
Query OK, 1 row affected (0.00 sec)

Let’s try to create the Foreign Key again:

mysql> ALTER TABLE employees ADD CONSTRAINT fk_department_id FOREIGN KEY idx_employees_department_id (department_id) REFERENCES departments(id);
Query OK, 1 row affected (0.24 sec)
Records: 1  Duplicates: 0  Warnings: 0

It worked this time.

So we have seen 5 different ways a Foreign Key creation can fail and possible solutions of how we can fix them. If you have encountered a reason not listed above, add them in the comments.

Categories
jQuery Web Development

jQuery DataTable: Sorting dynamic data

Try this code sample online!

Code samples for the this post is available in GitHub and can be previewed live using the link below.

TRY LIVE

jQuery DataTable is a powerful library to super charge your HTML tables. By default DataTable can sort your data based on the content of the cells. But if you are loading your table data dynamically and want to apply a custom sorting based on the DOM data, you can use DataTable’s custom sorting code:

function applyDomBasedSorting() {
    $.fn.dataTable.ext.order['data-sort'] = function(settings, col) {
        return this.api().column(col, {
            order: 'index'
        }).nodes().map(function(td, i) {
            return $(td).attr('data-sort');
        });
    }
}

data-sort could be anything. You can define your own sorting logic here. In this example, I would like to sort name by their second names. I’m setting this value into the data-sort attribute of the td cells.

Once you have defined your custom sorting logic like above, then you can use that when initializing your data table.

applyDomBasedSorting();
$('#employees').DataTable(
      {
        "columnDefs": [
          { "orderDataType": "data-sort", "targets": [1]}
        ],
      }
  );

GitHub Source code link: https://github.com/jiga-eng/jquery-code-samples/tree/master/datatable-code-samples/sorting

Categories
IntelliJ

Avoiding Wildcard imports in Java/Kotlin with IntelliJ

What is a wildcard import or a star import?

When you want to import multiple classes from the same package like this:

import com.example.exception.CustomerNotFoundExcetpion
import com.example.exception.ProductNotFoundExcetpion
import com.example.exception.ProductOutOfStockException
import com.example.exception.AdressNotFoundException

Java has an option to combine them into a single line using wildcard imports:

import com.example.exception.*

Is it bad?

Performance-wise, no. Using a wildcard import doesn’t actually import all the classes in the package. When your code is compiled, only the classes used from this package are added to the bytecode. So there is zero performance difference between wildcard import and explicit imports.

Then why should we avoid it?

  • Explicit imports clearly states what external classes the current class is directly using, provided that you don’t leave redundant imports in your code.
  • If there are two classes with the same name from different packages, it can introduce collision when using wildcard imports.
  • When multiple people are working in a project, wildcard imports can create confusion as to which classes are actually imported

Many large Java projects that I have worked with, have a checkstyle rule to disallow wildcard imports for the above reason.

Now that we have understood why explicit imports are better than implicit imports, let’s see how we can make IntelliJ always use explicit imports.

By default, IntelliJ will convert implicit imports into wildcard imports when it sees 5 import statements from the same package.

This setting can however by set to a large value like 99 to prevent the automatic wild card imports.

Goto Preferences -> Editor -> Code Style -> Java (or Kotlin) -> Update the following two values to 99:

  • Class count to use import with ‘*’
  • Names count to use static import

Click ‘Apply’ and close the dialog. Now do ‘Optimize Imports’ again to remove the wildcard imports automatically now and in the future.

More ‘Import’ options can be customized with IntelliJ. Follow this link for more customizations: https://www.jetbrains.com/help/idea/creating-and-optimizing-imports.html

The default Sun & Google’s Checkstyle rules also recommend avoiding star import by throwing this exception:

(imports) AvoidStarImport: Using the '.*' form of import should be avoided

To add this rule to your checkstyle configuration, add this line:

<module name="AvoidStarImport"/>
Categories
React

React: How to use Apollo with ‘Union Types’ in GraphQL

Apollo is one of the most popular React library to work with GraphQL APIs. However they don’t have native support when your APIs contain union types.

Let’s look at an example API that contains union types and how we can work with them using Apollo. Assuming you have an API like this:

{
  search(text: "an") {
    __typename
    ... on Human {
      name
      height
    }
    ... on Droid {
      name
      primaryFunction
    }
    ... on Starship {
      name
      length
    }
  }
}

that returns this response….

{
  "data": {
    "search": [
      {
        "__typename": "Human",
        "name": "Han Solo",
        "height": 1.8
      },
      {
        "__typename": "Human",
        "name": "Leia Organa",
        "height": 1.5
      },
      {
        "__typename": "Starship",
        "name": "TIE Advanced x1",
        "length": 9.2
      }
    ]
  }
}

If you use the above query via Apollo, you will see this warning messages in the browser console:

You are using the simple (heuristic) fragment matcher, but your queries contain union or interface types. Apollo Client will not be able to accurately map fragments. To make this error go away, use the `IntrospectionFragmentMatcher` as described in the docs: https://www.apollographql.com/docs/react/advanced/fragments.html#fragment-matcher

This is because Apollo by default uses a simple heuristics matching to match the response string into the Response object. We need to do some extra work to tell Apollo how to parse the response with union types.

Apollo has a separate section on their docs about this.

Step 1: Save the information about the fragment types in a separate file:

const fetch = require('node-fetch');
const fs = require('fs');

fetch(`${YOUR_API_HOST}/graphql`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    variables: {},
    query: `
      {
        __schema {
          types {
            kind
            name
            possibleTypes {
              name
            }
          }
        }
      }
    `,
  }),
})
  .then(result => result.json())
  .then(result => {
    // here we're filtering out any type information unrelated to unions or interfaces
    const filteredData = result.data.__schema.types.filter(
      type => type.possibleTypes !== null,
    );
    result.data.__schema.types = filteredData;
    fs.writeFile('./fragmentTypes.json', JSON.stringify(result.data), err => {
      if (err) {
        console.error('Error writing fragmentTypes file', err);
      } else {
        console.log('Fragment types successfully extracted!');
      }
    });
  });

The JSON file should look something like this:

{
  "__schema": {
    "types": [
      {
        "kind": "UNION",
        "name": "UnionSearchDetails",
        "possibleTypes": [
          {
            "name": "Human"
          },
          {
            "name": "Droid"
          },
          {
            "name": "Starship"
          }
        ]
      }
    ]
  }
}

Step 2: Create fragmentMatcher using the JSON file from the previous step:

import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import introspectionQueryResultData from './fragmentTypes.json';

const fragmentMatcher = new IntrospectionFragmentMatcher({
  introspectionQueryResultData
});

Step 3: Now include this fragmentMatcher in cache object and pass it to the Apollo client:

import ApolloClient from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';

// add fragmentMatcher code from step 2 here

const cache = new InMemoryCache({ fragmentMatcher });

const client = new ApolloClient({
  cache,
  link: new HttpLink(),
});

Now all done. The warnings and errors that you noticed previously should have gone away and the Response object from Apollo should contain the correct data.

How to use ‘Union types’ in tests and storybooks?

Now that you have fixed the problem for production code, how can we fix it for your tests or storybooks?

Apollo provides MockedProvider for this purpose. Here is a sample:

<MockedProvider mocks={mocks} addTypename cache={cache}>
     <MyComponenent />
</MockedProvider>

The important change here from the sample code is that addTypename has to be true, to allow Apollo to use the __typename in the response to map the object to the correct type.