Hibernate, java.util.Date and java.sql.Date Issues

Copied from The research Kitchen:

One issue that can crop up during unit testing is problems with date mapping. In SQL terms dates to a “day” level of precision can be specified using a DATE column and dates with a “time” element can be mapped using a TIMESTAMP (or MySQL DATETIME) column. These map respectively to the Java SQL types java.sql.Date and java.sql.Timestamp. Note that a java.util.Date object can specify times, up to a millisecond level of precision, whereas a java.sql.Timestamp object can handle nanosecond-level precision.

If we are using Hibernate to map a persistent class, and one of the fields is a day-level-precision Date field, we could map it like so:

In a unit test to exercise the persistence mapping, it could go something like the following:

Foo f = new Foo();
Calendar cal = Calendar.getInstance();
Date now = cal.getTime();
f.setStartDate(now);

and then test the retrieved persistent entity like so:

fooEntity = session.load(Foo.class, id);
assertEquals(f.getStartDate(), fooEntity.getStartDate());

The assertion will fail. The reason for this is that the call to fooEntity.getStartDate() returns an instance of java.sql.Date, whereas we are comparing against a java.util.Date. Since java.sql.Date is a subclass of java.util.Date, our tests will run without any ClassCastExceptions, but any equality checks will fail. The reason for this is apparent from the java.sql.Date javadoc:

To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date instance must be ‘normalized’ by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.

This means that any Date objects we retrieve from our Hibernate-mapped objects will have an effective time of midnight , i.e.something like 25-Jan-2006 00:00:00. We cannot just use the getTime() method to retrieve a long equaivalent of the date value either, as the they will ave the same problem.

What we can do is “normalize” the Date object before we persist it, like so:

private Date normalize(Calendar cal) {
cal.set(Calendar.MILLISECOND, 0);
cal.set(2006,0,25,0,0,0);
return cal.getTime();
}

...
Date now = normalize(cal);
event.setStartDate(now);

Now our asserts will pass without a problem.

Advertisements

Hibernate save, saveOrUpdate, persist, merge, update explanation with examples

Copied from Journaldev article :

Hibernate Session is the interface between java application and hibernate framework. Today we will look into Session important methods for saving and updating data in tables – save, saveOrUpdate, persist, update and merge.

Hibernate Save

As the method name suggests, hibernate save() can be used to save entity to database. We can invoke this method outside a transaction, that’s why I don’t like this method to save data. If we use this without transaction and we have cascading between entities, then only the primary entity gets saved unless we flush the session.

For our testing purposes we have two entity beans – Employee and Address.

Employee.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.journaldev.hibernate.model;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Cascade;
@Entity
@Table(name = "EMPLOYEE")
@Access(value=AccessType.FIELD)
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "emp_id")
    private long id;
    @Column(name = "emp_name")
    private String name;
    @Column(name = "emp_salary")
    private double salary;
    @OneToOne(mappedBy = "employee")
    @Cascade(value = org.hibernate.annotations.CascadeType.ALL)
    private Address address;
        //Getter setter methods
    @Override
    public String toString() {
        return "Id= " + id + ", Name= " + name + ", Salary= " + salary
                + ", {Address= " + address + "}";
    }
}
Address.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.journaldev.hibernate.model;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
@Entity
@Table(name = "ADDRESS")
@Access(value=AccessType.FIELD)
public class Address {
    @Id
    @Column(name = "emp_id", unique = true, nullable = false)
    @GeneratedValue(generator = "gen")
    @GenericGenerator(name = "gen", strategy = "foreign", parameters = { @Parameter(name = "property", value = "employee") })
    private long id;
    @Column(name = "address_line1")
    private String addressLine1;
    @Column(name = "zipcode")
    private String zipcode;
    @Column(name = "city")
    private String city;
    @OneToOne
    @PrimaryKeyJoinColumn
    private Employee employee;
        //Getter setter methods
    @Override
    public String toString() {
        return "AddressLine1= " + addressLine1 + ", City=" + city
                + ", Zipcode=" + zipcode;
    }
}

Here is a simple hibernate program where we are invoking save() method in different cases.

HibernateSaveExample.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Address;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateSaveExample {
    public static void main(String[] args) {
        
        // Prep Work
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        
        //save example - without transaction
        Session session = sessionFactory.openSession();
        Employee emp = getTestEmployee();
        long id = (Long) session.save(emp);
        System.out.println("1. Employee save called without transaction, id="+id);
        session.flush(); //address will not get saved without this
        System.out.println("*****");
        
        //save example - with transaction
        Transaction tx1 = session.beginTransaction();
        Session session1 = sessionFactory.openSession();
        Employee emp1 = getTestEmployee();
        long id1 = (Long) session1.save(emp1);
        System.out.println("2. Employee save called with transaction, id="+id1);
        System.out.println("3. Before committing save transaction");
        tx1.commit();
        System.out.println("4. After committing save transaction");
        System.out.println("*****");
        
        //save example - existing row in table
        Session session6 = sessionFactory.openSession();
        Transaction tx6 = session6.beginTransaction();
        Employee emp6 =  (Employee) session6.load(Employee.class, new Long(20));
        
        //update some data
        System.out.println("Employee Details="+emp6);
        emp6.setName("New Name");
        emp6.getAddress().setCity("New City");
        
        long id6 = (Long) session6.save(emp6);
        emp6.setName("New Name1"); // will get updated in database
        System.out.println("5. Employee save called with transaction, id="+id6);
        System.out.println("6. Before committing save transaction");
        tx6.commit();
        System.out.println("7. After committing save transaction");
        System.out.println("*****");
        
        // Close resources
        sessionFactory.close();
    }
    public static Employee getTestEmployee() {
        Employee emp = new Employee();
        Address add = new Address();
        emp.setName("Test Emp");
        emp.setSalary(1000);
        add.setAddressLine1("Test address1");
        add.setCity("Test City");
        add.setZipcode("12121");
        emp.setAddress(add);
        add.setEmployee(emp);
        return emp;
    }
}

When we execute above program, it produces following output.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
1. Employee save called without transaction, id=149
Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
*****
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
2. Employee save called with transaction, id=150
3. Before committing save transaction
Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
4. After committing save transaction
*****
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee Details=Id= 20, Name= Kumar1, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Blr, Zipcode=12121}
5. Employee save called with transaction, id=20
6. Before committing save transaction
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=?
7. After committing save transaction
*****

Few important points that we can confirm from above output are:

  • We should avoid save outside transaction boundary, otherwise mapped entities will not be saved causing data inconsistency. It’s very normal to forget flushing the session because it doesn’t throw any exception or warnings.
  • Hibernate save method returns the generated id immediately, this is possible because primary object is saved as soon as save method is invoked.
  • If there are other objects mapped from the primary object, they gets saved at the time of committing transaction or when we flush the session.
  • For objects that are in persistent state, save updates the data through update query. Notice that it happens when transaction is committed. If there are no changes in the object, there wont be any query fired. If you will run above program multiple times, you will notice that update queries are not fired next time because there is no change in the column values.
  • Hibernate save load entity object to persistent context, if you will update the object properties after the save call but before the transaction is committed, it will be saved into database.

Hibernate Persist

Hibernate persist is similar to save (with transaction) and it adds the entity object to the persistent context, so any further changes are tracked. If the object properties are changed before the transaction is committed or session is flushed, it will also be saved into database.

Second difference is that we can use persist() method only within the boundary of a transaction, so it’s safe and takes care of any cascaded objects.

Finally, persist doesn’t return anything so we need to use the persisted object to get the generated identifier value. Let’s look at hibernate persist with a simple program.

HibernatePersistExample.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernatePersistExample {
    public static void main(String[] args) {
        
        // Prep Work
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); 
        
        //persist example - with transaction
        Session session2 = sessionFactory.openSession();
        Transaction tx2 = session2.beginTransaction();
        Employee emp2 = HibernateSaveExample.getTestEmployee();
        session2.persist(emp2);
        System.out.println("Persist called");
        emp2.setName("Kumar"); // will be updated in database too
        System.out.println("Employee Name updated");
        System.out.println("8. Employee persist called with transaction, id="+emp2.getId()+", address id="+emp2.getAddress().getId());
        tx2.commit();
        System.out.println("*****");
        
        // Close resources
        sessionFactory.close();
    }
}

Output produced by above code is:

1
2
3
4
5
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
8. Employee persist called with transaction, id=158, address id=158
Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
*****

Notice that first employee object is inserted, then at the time of transaction commit, update query is executed to update the name value. Also mapped object address is saved into database.

Hibernate saveOrUpdate

Hibernate saveOrUpdate results into insert or update queries based on the provided data. If the data is present in the database, update query is executed.

We can use saveOrUpdate() without transaction also, but again you will face the issues with mapped objects not getting saved if session is not flushed.

One important difference between save and saveOrUpdate is that it adds the entity object to persistent context and track any further changes. Any further changes are saved at the time of committing transaction, like persist.

HibernateSaveOrUpdateExample.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateSaveOrUpdateExample {
    public static void main(String[] args) {
        
        // Prep Work
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        
        //saveOrUpdate example - without transaction
        Session session5 = sessionFactory.openSession();
        Employee emp5 = HibernateSaveExample.getTestEmployee();
        session5.saveOrUpdate(emp5);
        System.out.println("*****");
        
        //saveOrUpdate example - with transaction
        Session session3 = sessionFactory.openSession();
        Transaction tx3 = session3.beginTransaction();
        Employee emp3 = HibernateSaveExample.getTestEmployee();
        session3.saveOrUpdate(emp3);
        emp3.setName("Kumar"); //will be saved into DB
        System.out.println("9. Before committing saveOrUpdate transaction. Id="+emp3.getId());
        tx3.commit();
        System.out.println("10. After committing saveOrUpdate transaction");
        System.out.println("*****");
        
        
        Transaction tx4 = session3.beginTransaction();
        emp3.setName("Updated Test Name"); //Name changed
        emp3.getAddress().setCity("Updated City");
        session3.saveOrUpdate(emp3);
        emp3.setName("Kumar"); //again changed to previous value, so no Employee update
        System.out.println("11. Before committing saveOrUpdate transaction. Id="+emp3.getId());
        tx4.commit();
        System.out.println("12. After committing saveOrUpdate transaction");
        System.out.println("*****");
        // Close resources
        sessionFactory.close();
    }
}

Above program produces following output.

1
2
3
4
5
6
7
8
9
10
11
12
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
*****
Hibernate: insert into EMPLOYEE (emp_name, emp_salary) values (?, ?)
9. Before committing saveOrUpdate transaction. Id=166
Hibernate: insert into ADDRESS (address_line1, city, zipcode, emp_id) values (?, ?, ?, ?)
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
10. After committing saveOrUpdate transaction
*****
11. Before committing saveOrUpdate transaction. Id=166
Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=?
12. After committing saveOrUpdate transaction
*****

Notice that without transaction, only Employee gets saved and address information is lost.

With transaction employee object is tracked for any changes, thats why in last call there is no update in Employee table even though the value was changed in between, final value remains same.

Hibernate update

Hibernate update should be used where we know that we are only updating the entity information. This operation adds the entity object to persistent context and further changes are tracked and saved when transaction is committed. Let’s check this behavior with a simple program.

HibernateUpdateExample.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateUpdateExample {
    public static void main(String[] args) {
        // Prep Work
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        Employee emp = (Employee) session.load(Employee.class, new Long(101));
        System.out.println("Employee object loaded. " + emp);
        tx.commit();
        // update example
        emp.setName("Updated name");
        emp.getAddress().setCity("Bangalore");
        Transaction tx7 = session.beginTransaction();
        session.update(emp);
        emp.setName("Final updated name");
        System.out.println("13. Before committing update transaction");
        tx7.commit();
        System.out.println("14. After committing update transaction");
        // Close resources
        sessionFactory.close();
    }
}

When we execute above program for the first time, we get following output.

1
2
3
4
5
6
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee object loaded. Id= 101, Name= Test Emp, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Test City, Zipcode=12121}
13. Before committing update transaction
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
Hibernate: update ADDRESS set address_line1=?, city=?, zipcode=? where emp_id=?
14. After committing update transaction

On further execution, we get following output.

1
2
3
4
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee object loaded. Id= 101, Name= Final updated name, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121}
13. Before committing update transaction
14. After committing update transaction

Notice that there are no updates fired after first execution because there are no update in values. Also notice the employee name is “Final updated name” that we set after invoking update() method. This confirms that hibernate was tracking the object for any changes and at the time of committing transaction, this value got saved.

Hibernate Merge

Hibernate merge can be used to update existing values, however this method create a copy from the passed entity object and return it. The returned object is part of persistent context and tracked for any changes, passed object is not tracked. This is the major difference with merge() from all other methods. Let’s look at this with a simple program.

HibernateMergeExample.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateMergeExample {
    public static void main(String[] args) {
        // Prep Work
        SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        Employee emp = (Employee) session.load(Employee.class, new Long(101));
        System.out.println("Employee object loaded. " + emp);
        tx.commit();
         //merge example - data already present in tables
         emp.setSalary(25000);
         Transaction tx8 = session.beginTransaction();
         Employee emp4 = (Employee) session.merge(emp);
         System.out.println(emp4 == emp); // returns false
         emp.setName("Test");
         emp4.setName("Kumar");
         System.out.println("15. Before committing merge transaction");
         tx8.commit();
         System.out.println("16. After committing merge transaction");
        // Close resources
        sessionFactory.close();
    }
}

Output in first execution is:

1
2
3
4
5
6
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee object loaded. Id= 101, Name= Final updated name, Salary= 1000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121}
false
15. Before committing merge transaction
Hibernate: update EMPLOYEE set emp_name=?, emp_salary=? where emp_id=?
16. After committing merge transaction

In further execution, output produced is:

1
2
3
4
5
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
Employee object loaded. Id= 101, Name= Kumar, Salary= 25000.0, {Address= AddressLine1= Test address1, City=Bangalore, Zipcode=12121}
false
15. Before committing merge transaction
16. After committing merge transaction

Notice that the entity object returned by merge() is different from the passed entity. Also notice that in further execution, name is “Kumar”, this is because the returned object is tracked for any changes.

That’s all for hibernate save and update methods, I hope that examples above will help you in clarifying any doubts you have.

Effective Java Summary

Item 58: Check v/s unchecked exception

Three kinds of throwables

Throwables Checked Recoverable
checked exceptions Y Y
runtime exceptions N N
errors N N

Principle

  1. Use checked exceptions for conditions from which the caller can reasonably be expected to recover.
  2. Code that parses the string representation of an exception is likely to be non portable and fragile. Since the toString() implementation may change from release to release (Item 10).
  3. Provide methods that furnish information that could help the caller to recover.

    For example, suppose a checked exception is thrown when an attempt to make a purchase with a gift card fails because the card doesn’t have enough money left on it. The exception should provide an accessor method to query the amount of the shortfall, so the amount can be relayed to the shopper

  4. Use runtime exceptions to indicate programming errors. -The great majority of runtime exceptions indicate precondition violations. (e.g. ArrayIndexOutOfBoundException).

Note

All of the unchecked throwables you implement should subclass RuntimeException directly or indirectly.

Never use behaviorally identical to ordinary checked exceptions (which are subclasses of Exception but not RuntimeException).

Sub Class of Exceptions:

The unchecked exceptions classes are the class RuntimeException and its subclasses, and the class Error and its subclasses. All other exception classes are checked exception classes. The Java API defines a number of exception classes, both checked and unchecked. Additional exception classes, both checked and unchecked, may be declared by programmers. See §11.5 for a description of the exception class hierarchy and some of the exception classes defined by the Java API and Java virtual machine.

The following picture illustrates the Exception hierarchy:

alt text

The class Error and its subclasses are exceptions from which ordinary programs are not ordinarily expected to recover and, as explained in 11.5 The Exception Hierarchy:

The class Error is a separate subclass of Throwable, distinct from Exception in the class hierarchy, to allow programs to use the idiom:

} catch (Exception e) {

to catch all exceptions from which recovery may be possible without catching errors from which recovery is typically not possible.

To summarize, RuntimeException are a subset of unchecked exceptions for exceptions from which recovery is possible (but unchecked exception is not a synonym of RuntimeException as many are answering here).

Transaction:

Transactions are roll-back automatically for Unchecked exception but needed to be done manually for checked exception (or change in declaration for automatic roll-back).

Summary

Use checked exceptions for recoverable conditions and runtime exceptions for programming errors. Of course, the situation is not always black and white.

Sublime Plugins

Copied from – http://kroltech.com/2013/10/sublime-text-my-new-favorite-editor/ . Just for reference.

Sublime Text – My New Favorite Editor!

I’ve been using Sublime Text 2 exclusively for about 2 months now and I absolutely love it. More and more every day! Even though it could be considered a pretty basic editor, don’t let that fool you. There are so many plugins and customizations available it’s incredible. So I wanted to run down my basic setup with Sublime along with some tips, tricks, and notable plugins.

Sublime Package Control

Before you do anything, you need to have Sublime Package Control installed. Think of npm or nuget or any other package manager. It’s an absolute must and makes finding and installing plugins a breeze!

https://sublime.wbond.net/installation

Once installed (and restarted) simply press ⌘ – Shift – P / Control – Alt – P to open the Goto Anything dialog. Type Install and press Enter. Search to your heart’s content! Most, if not all, of the plugins listed in the rest of this article can be installed via Package Control.

Automated jsHint(ing) on Save

For Javascript developers using Sublime, here are some steps to have a nice jsHint automated build process:

Set some user settings for Trailing Spaces:

{
    "trailing_spaces_highlight_color": "invalid",
    "trailing_spaces_include_current_line": false
}

Some Sublime optional settings (Preferences -> Settings – User):

{
    "rulers":
    [
        80, 120
    ],
    "tab_size": 4,
    "translate_tabs_to_spaces": true,
    "trim_trailing_white_space_on_save": true,
    "use_tab_stops": true,
    "ensure_newline_at_eof_on_save": true,
}

You should probably restart Sublime again after all of that.

Now when you edit any .js files:

  1. Execute jsFormat (depends on how you configured keyboard shortcuts) which will fix most tabbing and spacing alignment issues. (If you have no code highlighted the entire file will auto format, if you highlight code the formatting will apply only to that selection.)
  2. Save and you will get the jsHint report popup in a console window. (Not only that, but the trailing spaces everywhere will be automatically trimmed.)

Execute Sublime from the command line (mac):

In order to be able to launch sublime from the command line, you need to setup a symlink. The easiest way to do this is with the following command:

ln -s /Applications/Sublime\ Text\ 2.app/Contents/SharedSupport/bin/subl /usr/local/bin/sublime

Git integration:

There are 2 excellent plugins that work really well if you find yourself working on git repos a lot:

If you’d prefer to use Sublime as your default Git related editor (i.e. to edit commit messages and manage rebasing) then execute the following command (assuming you created the symlink for Sublime above so that you can execute it from the command line):

git config --global core.editor "sublime -w"

Other miscellaneous plugins:

Some other helpful random settings (that should be self explanatory):

"bold_folder_labels": true,
"draw_indent_guides": true,
"highlight_line": true,
"highlight_modified_tabs": true,
"match_brackets": true,
"match_brackets_angle": true,
"match_brackets_braces": true,
"match_brackets_content": true,
"match_brackets_square": true,
"remember_open_files": true,
"remember_open_folders": true,
"scroll_past_end": true,
"scroll_speed": 2,

Snippets:

Sublime includes a lot of predefined code snippets by default. To use snippets, just start typing and a dropdown will instantly appear. Type something like “for” (no quotes) and then TAB and you will see JavaScript for loop code output instantly. You can also open the Goto Anything dialog and type Snippet to get a list of all the Snippets. To create a new Snippet, simply goto Tools->New Snippet… (read more about Snippets) As a bonus, you can install snippets for popular libraries and frameworks via the Package Installer (hint, install the jQuery Snippet package!).

Keyboard Commands and Shortcuts:

There are a ton of keyboard shortcuts for Sublime, as well as the awesome ability to very quickly and easily create your own. Take a look at the default key bindings to get an idea of how to create your own or overwrite an existing key bind. Then edit your own:

Preferences->Key Bindings – User:

[
// git specific shortcuts:
{ "keys": ["ctrl+shift+d"], "command": "git_diff" }
]

*Note: If you plan to add more than one custom shortcut, be sure to place a comma and the end of every line but the last. In the example above, there is only 1 line so there is no trailing comma.

Some of the most important keyboard shortcuts:

  • ⌘ – P (Ctrl – P) = Goto anything
  • ⌘ – T (Ctrl – T) = Goto file
  • ⌘ – R (Ctrl – R) = Goto function (inside file)
  • Control – G = Goto line number

Hopefully you find these tips, tricks, shortcuts, and plugins useful! The best tip I can give is to always Google “sublime ____” no matter what it is you are trying to do, think you should be able to do, or wish you could do. I can almost guarantee someone created a plugin for it!