Working with Google Maps Javascript API V3

Google Maps Javascript API V3 is an awesome API provided by Google. Today I will give you a little flavor about this API. Later I will write about some advance features.

Here is a simple tool, created using this API. Click on the marker, the Latitude and Longitude position will be displayed in a window and also in the textbox. If you set a Latitude, Longitude point in the textbox and click on the button, that point will be shown in the map with a marker.

Latitude

Longitude


Now I'm going to show you, how you can make this tool..

First load the Google Maps Javascript API and the latest jQuery version . Then design the user interface.

 
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="http://zmodal.googlecode.com/files/jquery-1.6.1.min.js"></script>

<div style="float:left; width:200px; border:1px solid #CCCCCC;">
        Latitude <input type="text" id="tbLattitude"/><br/>
        Longitude <input type="text" id="tbLongitude"/><br/>
        <input type="button" name="btCal" value="Show in Map" onclick="return showInMap();" />
    </div>
    <div id="map_canvas" style="float:left;width: 400px; height: 400px; border: 2px solid #999;margin-left:10px;">
    </div>

The DIV element with id 'map_canvas' will be the container of the Map. This id will be required when you create the map object to display in this div.

Now come to the Javascript part..

Set the window onLoad callback method and in that method, call the LoadMap method with initial latitude,longitude.

 
google.maps.event.addDomListener(window, 'load', initializeMap);
function initializeMap() {
  LoadMap(23.70992, 90.40714);
}

In the LoadMap method first create a LatLng object using the lat, long parameter

 
function LoadMap(lat, longitude) {
var latlng = new google.maps.LatLng(lat, longitude);
Create a Map object using map options and the container ID
 
var myOptions = {
  zoom: 12,
  center: latlng, // previously created LatLng object
  mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

For the information window first create the content of the window then create a InfoWindow object using the content. This object will be later used in the onClick event of the Marker.

var contentString = '
' + 'Latitude : '+lat+'
Longitude : ' + longitude + '' '
'; var infowindow = new google.maps.InfoWindow({ content: contentString });

Now create the Marker object using the LatLng and Map object.

var marker = new google.maps.Marker({
  position: latlng,
  map: map,
  title: 'Location',
  draggable: true,
  animation: google.maps.Animation.DROP
});

Finally add an event listener for the Marker object. First open the InfoWindow object then call the method which set LatLng value to the textbox.

  google.maps.event.addListener(marker, 'click', function (event) {
    infowindow.open(map, marker);
    setLatLongToTextBox(event.latLng);
  });

}
Here is the setLatLongToTextBox and showInMap method
function setLatLongToTextBox(latlong) {
  var latstr = latlong + '';
  var value = latstr.slice(1, latstr.length - 1);
  var latlongs = value.split(",");
  $("#tbLattitude").attr("value", latlongs[0]);
  $("#tbLongitude").attr("value", latlongs[1]);
}

//this method is used as the onclick method of the button 
function showInMap() {
  var lat = $("#tbLattitude").attr("value");
  var longitude = $("#tbLongitude").attr("value");
  LoadMap(lat, longitude);
  return false;
}

Working with Google Chart Tools : Create a Geochart

Geochart can be a handy tool if you want to represent the demographic behavior of your service. In my recent project for Bangladesh Post Office I used this tool to represent the usage of their service in each Division of Bangladesh. Another big example is the Google Analytics where you can view the location based visitor information of your site. Here I am going to show you how you can use this in your project.

First load the Google's Javascript API
<script src="https://www.google.com/jsapi" type="text/javascript">  
</script> 

Now create a DIV element and give it an ID. This id will be required when you create the chart object to display in this div.

<div id="map">
    </div>

In your Javascript code first load the geomap package and set the onLoadCallback method name.

<script type="text/javascript">
 google.load('visualization', '1', { 'packages': ['geomap'] });
 google.setOnLoadCallback(drawGeoChart);

In the callback method first create a DataTable object add two columns. Just give a suitable name as per your requirement.

 function drawGeoChart() {
            var data = new google.visualization.DataTable();
            data.addRows(6);
            data.addColumn('string', 'Country');
            data.addColumn('number', 'Visit');

Now set some value to the DataTable. The first column can be an Address, country name, region name locations, or US metropolitan area codes. For country and region name follow this ISO-3166 code or text equivalent to the code. The second column will be the value of the area.

            data.setValue(0, 0, 'Germany');
            data.setValue(0, 1, 600);
            data.setValue(1, 0, 'United States');
            data.setValue(1, 1, 500);
            data.setValue(2, 0, 'Bangladesh');
            data.setValue(2, 1, 400);
            data.setValue(3, 0, 'Canada');
            data.setValue(3, 1, 200);
            data.setValue(4, 0, 'France');
            data.setValue(4, 1, 200);
            data.setValue(5, 0, 'RU');
            data.setValue(5, 1, 300);
Finally configure some property of the chart and draw it using the data previously set.
  var regionOptions = {};
  regionOptions['width'] = '400';
  regionOptions['height'] = '250';
  // Look the div id is used here to create the chart object 
  var regionChart = new  google.visualization.GeoMap(document.getElementById('map'));
  regionChart.draw(data, regionOptions);
        
}
</script>
And here is the outcome. On mouse over you can view the data of the area



You can load the chart data by a webservice call. For C# see my previous blog. Visit this link to know more about Geochart.

Working with Google Chart Tools in C# .NET : Create a Simple Pie Chart

If you want to load a chart asynchronously in C# . NET, Google Chart Tools will be the perfect choice for you. It is easy to use and enough flexible to customize. Suppose you want to show how many students in your class like Pizza, Burger, Hotdog, and Fried Chicken in a Pie chart. Here I will show you how to load the students' data from server side using WebService and show it in a chart asynchronously.

First create a new WebService file suppose GoogleChart.asmx . In this file create a Public Class named FoodLikingCount

    public class FoodLikingCount
    {
        public int PizzaCount { get; set; }
        public int BurgerCount { get; set; }
        public int HotdogCount { get; set; }
        public int FriedChickenCount { get; set; }
    }

After the class declaration add the following line

[System.Web.Script.Services.GenerateScriptType(typeof(FoodLikingCount))]

It will enable you to use the FoodLikingCount object in your Javascript code.

Create a new WebMethod in the WebService class named GetFoodLikingCountData

[WebMethod]
public FoodLikingCount GetFoodLikingCountData()
{
       FoodLikingCount countModel = new FoodLikingCount 
       {
           PizzaCount = 12,
           BurgerCount = 16,
           HotdogCount = 8,
           FriedChickenCount = 4,
       };
       // you can also load data from your database here

       return countModel ;
}

Now come to client side code. Create an aspx file named GoogleChartToolTest.aspx and add this line between head tag.

 <script src="https://www.google.com/jsapi" type="text/javascript">
 </script> 

Create a DIV element and give it an ID. This id will be required when you create the chart object to display in this div. Also add a ScriptManager to call your webservice method.

    <form id="form1" runat="server">
        <asp:ScriptManager ID="sm1" runat="server">
            <Services>
                 <asp:ServiceReference Path="~/[your_package]/GoogleChart.asmx" />
            </Services>
        </asp:ScriptManager>
    </form>
    <div id="pie_chart">
    </div>

Here is the Javascript code which you require to load data through the webservice call, create, and show chart in the div.

<script type="text/javascript">

//load the corechart package, the pie chart is in this package
google.load('visualization', '1', { packages: ['corechart'] });

//provide the method name which you want to call as onload callback
google.setOnLoadCallback(loadFoodLikingChart);

function loadFoodLikingChart()
{
       [your_package].GoogleChart.GetFoodLikingCountData(
            function (ws_rsp) {
              var foodLikingData= new google.visualization.DataTable();
              foodLikingData.addColumn('string', 'Food');
              foodLikingData.addColumn('number', 'Count');
              foodLikingData.addRows(4);
              
              foodLikingData.setValue(0, 0, "Pizza");
              foodLikingData.setValue(0, 1, ws_rsp.PizzaCount );
              foodLikingData.setValue(1, 0, "Burger");
              foodLikingData.setValue(1, 1, ws_rsp.BurgerCount );
              foodLikingData.setValue(2, 0, "Hotdog");
              foodLikingData.setValue(2, 1, ws_rsp.HotdogCount );
              foodLikingData.setValue(3, 0, "Fried Chicken");
              foodLikingData.setValue(3, 1, ws_rsp.FriedChickenCount );

              var options = {};
              options ['width'] = '400';
              options ['height'] = '250';
              options ['chartArea'] = { left: 20, top: 20, width: '95%', height: '90%' };

              // Look the div id is used here to create the chart object
              var chart = new google.visualization.PieChart(document.getElementById('pie_chart'));
              chart.draw(foodLikingData,options);
            },
            function (e) {
               alert("Error");
           }
      );
}
</script>

The result will be like this.

Visualize the DataTable as a two dimensional array. It will help you to understand the above code. Here is the Google Chart Gallery. You will get a lot of example there.

zModal, An Easy to Use jQuery Modal Plugin



There are lots of jQuery modal plugin available in the web. For my current project I need one which, I can easily customize. I realized creating a modal by myself is the best way for gaining maximum freedom.

It is very simple and easy to use and customizable. You can give it a try. Here I will describe how to use it.

First download all the required files from here and include in the page.

Create a DIV and give it an id and set the display property 'none'.

<div id="modalContent" style="width:400px; display:none;">
</div>
You can insert any content between the DIV tag.

Now place a button, the onclick event of which will show the modal
<input type="button" name="name2" value="Show Modal" 
onclick="$('#modalContent').showModal();" />
Here is an example. Click on the button and a modal will pop up.


<div id="modalContent" style="width:400px; height: 150px; display: none;">
<p style="padding-left:20px;">
modalContent:
Click the close button to hide the modal
You can also press ESCAPE button to hide the modal
</p>
</div>
<input type="button" name="name2" value="Show Modal" 
onclick="$('#modalContent').showModal();" />

There are some configurable options for the modal.
setModalButtonCss : Set True if you want to display all buttons contained in the modal in a zModal style.
hideDefaultClose : Set True if you want to hide the default close button.
opacity : You can control the opacity of the background with this parameter.
bgColor : You can change the background color with this parameter.

Here is an example with all the options are set.
<div id="modalContent2" style="width:400px; display:none;">
<p>
User Name:<br />
<input id="tbUname" type="text" name="uName">
</p>
<p>
Password:<br />
<input id="tbPass" type="text" name="pass">
</p>
<p>
<input type="button" name="login" value="Login" onclick="$('#modalContent2').hideModal()" />
</p>
</div>
<input type="button" name="name" value="Show Modal 1" 
onclick="$('#modalContent2').showModal({'setModalButtonCss': 'True', 
'hideDefaultClose' : 'True', 
'opacity' : '.2', 
'bgColor' : '#7FCFF9' });" />
Click on the button to view the example

If you want to hide your modal like the onclick event of the Login button write this code
$('#divID').hideModal();

Remember Old School OO Principle While Using RegularExpressionValidator

I'm sure all of you are frequently using RegularExpressionValidator in your project. But are sure you are not repeating same expression in multiple pages? Is your code impervious to Change? If you are a bit careful while writing code, you can avoid this. And your friend will be 'Inheritance'.

Suppose you are using a RegularExpressionValidator to validate phone number. You may possibly going to write following code block

<asp:RegularExpressionValidator ID="revPhoneNumber" Display="Dynamic" ErrorMessage="Valid phone no required." ControlToValidate="tbPhoneNumber" ValidationExpression="^\d{8,}$" runat="server">*</asp:RegularExpressionValidator>

If you need this Validator in more than one page, then writing the same code block in every page obviously produces code duplication. Moreover if your project manager asks you to allow '+' at the beginning of the phone number then you have to change the regular expression in all pages. That will be surely a painful task for you. You can make your life easy by following approach.

Create your own validator by inheriting RegularExpressionValidator. Assign a regular expression to the ValidationExpression property

namespace TestValidator.Validators
{
    public class PhoneNumberValidator : RegularExpressionValidator
    {
        public PhoneNumberValidator()
        {
            ValidationExpression = "^\\d{8,}$";
        }
    }
}

To use your own PhoneNumberValidator first add this in the Registry
<%@ Register Assembly="TestValidator(Project Name)" Namespace="TestValidator.Validators" TagPrefix="myvalidators" %>

Then use this in the following way

<myvalidators:PhoneNumberValidator ID="revPhoneNumber" Display="Dynamic" ErrorMessage="Valid phone no required." ControlToValidate="tbPhoneNumber" runat="server">*</myvalidators:PhoneNumberValidator>

Now it is a matter of seconds to accomplish what your project manager wants.

Working With GXT (Ext GWT) Grid : Add Filter Functionality

Yesterday I was looking for something new (new widgets, new functionality) in the latest GXT version (2.2.1) and found that, it is now providing grid filtering support. You can add MS Excel like filtering option in your application through this. I think it was the most demanded and expected feature from the GXT developers which can be highly utilized in Enterprise Reporting. I am going to describe how to add this functionality in GXT Grid.

Create a new project named GxtFilterGrid and add GXT library in the project. As like my previous blogs about GXT Grid I have used the same Employee model and TestData class for generating data. You will find the code of these classes here. Go to the onModuleLoad method of GxtFilterGrid class and remove all the auto generated code of this method.

First create a list of ColumnConfig and a ColumnModel from this list.

List<ColumnConfig> configs = new ArrayList<ColumnConfig>();

  ColumnConfig column = new ColumnConfig();
  column.setId("name");
  column.setHeader("Employee Name");
  column.setWidth(200);
  configs.add(column);

  column = new ColumnConfig("department", "Department", 150);
  column.setAlignment(HorizontalAlignment.LEFT);
  configs.add(column);

  column = new ColumnConfig("designation", "Designation", 150);
  column.setAlignment(HorizontalAlignment.LEFT);
  configs.add(column);

  column = new ColumnConfig("salary", "Slary", 100);
  column.setAlignment(HorizontalAlignment.RIGHT);
  final NumberFormat number = NumberFormat.getFormat("0.00");
  GridCellRenderer<Employee> checkSalary = new GridCellRenderer<Employee>() {
   @Override
   public Object render(Employee model, String property,
     com.extjs.gxt.ui.client.widget.grid.ColumnData config,
     int rowIndex, int colIndex, ListStore<Employee> store,
     Grid<Employee> grid) {
    double val = (Double) model.get(property);
    String style = val < 70000 ? "red" : "green";
    return ""
      + number.format(val) + "";

   }
  };
  column.setRenderer(checkSalary);
  configs.add(column);

  column = new ColumnConfig("joiningdate", "Joining Date", 100);
  column.setAlignment(HorizontalAlignment.RIGHT);
  column.setDateTimeFormat(DateTimeFormat.getShortDateFormat());
  configs.add(column);

  ColumnModel cm = new ColumnModel(configs);

Now create different types of filters like Numeric, String, Date, etc. Constructor of these filter classes takes the column name to bind the specific filter with a specific column.

NumericFilter numericFilter = new NumericFilter("salary");
StringFilter nameFilter = new StringFilter("name");
StringFilter designationFilter = new StringFilter("designation");
DateFilter dateFilter = new DateFilter("joiningdate"); 

You can also add a ListStore as a filtering option with the help of ListFilter. For adding a list filter, create a ListStore of ModelData or your own BaseModel class and add this as the source of ListFilter.

ListStore<ModelData> departmentStore = new ListStore<ModelData>();
departmentStore.add(departement("General Administration"));
departmentStore.add(departement("Information Technology"));
departmentStore.add(departement("Marketing"));
departmentStore.add(departement("Accounts"));
 //department method is stated later
ListFilter listFilter = new ListFilter("department", departmentStore);
listFilter.setDisplayProperty("departmentname");

Display Property of the ListFilter will be the key name of your model data. Now create a GridFilters instance and add all the filters created above with this instance.

GridFilters filters = new GridFilters();
filters.setLocal(true);
filters.addFilter(numericFilter);
filters.addFilter(nameFilter);
filters.addFilter(designationFilter);
filters.addFilter(dateFilter);
filters.addFilter(listFilter);

Finally create a ListStore of Employee Model and, a Grid from this ListStore and ColumnModel. Add the GridFilters instance as the Plugin of the Grid.

ListStore<Employee> employeeList = new ListStore<Employee>();
employeeList.add(TestData.getEmployees());

Grid<Employee> grid = new Grid<Employee>(employeeList, cm);
grid.setStyleAttribute("borderTop", "none");
grid.setAutoExpandColumn("name");
grid.setBorders(true);
grid.setStripeRows(true);
grid.getView().setForceFit(true);
grid.setColumnLines(true);
grid.addPlugin(filters);

ContentPanel cp = new ContentPanel();  
cp.setBodyBorder(false);  
cp.setHeading("Employee List With Filtering Option");  
cp.setButtonAlign(HorizontalAlignment.CENTER);  
cp.setLayout(new FitLayout());  
cp.setSize(700, 300); 
cp.add(grid);  
RootPanel.get().add(cp);
Here is the code of department method which is used previously.
private ModelData departement(String departement) {
  ModelData model = new BaseModelData();
  model.set("departmentname", departement);
  return model;
}

That's all. Run the project and the output will be like this

Java Image Utility

Few days ago I did some image manipulation tasks like resizing, cropping, etc. java awt provides some useful functionality to do this type of tasks. Here I am going to share how I accomplish the tasks and finally and ImageUtility Class which you can use in your project.

Image Resizing
First read the image with the ImageIO which returns a BufferedImage. Then create another BufferedImage instance with the new width, height and image type.

BufferedImage originalImage = ImageIO.read(imageFile); 
BufferedImage scaledBI = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);

Now get the Graphics2D component of the new scaled image and draw it.

g.drawImage(originalImage, 0, 0, 100, 100, null);
g.dispose();

If you want to preserve the image quality, add following line of code before disposing the graphics component.

g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

It's simple, is not it?

Image Croping

Read the image with ImageIO as stated previously and get the sub image of the original image.

BufferedImage originalImage = ImageIO.read(imageFile); 
originalImage .getSubimage(0,0, 100, 100);

First two parameter of the getSubimage method is the x,y coordinate, from where you want to begin cropping.


Get Byte Array of an Image

Sometimes you need this specially when you want to save an image in database in blob data type . We can get byte[] of an image with the help of ByteArrayOutputStream and ImageIO class.


BufferedImage originalImage = ImageIO.read(imageFile); 
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(originalImage , getImageExtension(), baos);
//getImageExtension method is stated later
baos.flush();
byte[] imageData = baos.toByteArray();
baos.close();

ImageUtility.java

All the above actions can be encapsulated into a simple ImageUtility class.

import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import org.openide.util.Exceptions;

/**
 *
 * @author ratul
 */
public class ImageUtility
{
    private File imageFile;
    private BufferedImage image;
    public ImageUtility()
    {
    }

    public ImageUtility(File imageFile)
    {
        try
        {
            this.imageFile = imageFile;
            image = ImageIO.read(imageFile);
        }
        catch (IOException ex)
        {
            Exceptions.printStackTrace(ex);
        }
    }

    public ImageUtility(File imageFile, BufferedImage image)
    {
        this.imageFile = imageFile;
        this.image = image;
    }


    public File getImageFile()
    {
        return imageFile;
    }

    public void setImageFile(File imageFile)
    {
        this.imageFile = imageFile;
    }

    public BufferedImage getImage()
    {
        return image;
    }

    public void setImage(BufferedImage image)
    {
        this.image = image;
    }
    
    public String getImageExtension()
    {
        String fName = imageFile.getName();
        return fName.substring(fName.indexOf(".")+1, fName.length());
    }
    public BufferedImage getResizedCopy(int scaledWidth, int scaledHeight, boolean preserveAlpha)
    {
        return getResizedCopyOfImage(image, scaledWidth, scaledHeight, preserveAlpha);
    }
    
    public byte[] getByte()
    {
        return getByteOfImage(image);
    }
    public ImageIcon getImageIcon()
    {
        return new ImageIcon(image);
    }
    public BufferedImage getCropedImage(int x, int y, int width, int height)
    {
        return getCropedImageOfImage(image, x, y, width, height);
    }
    public BufferedImage getCropedImageFromCenter(Dimension panelDimension,int clipedWidth, int clipedHeight)
    {
        return getCropedImageOfImageFromCenter(image, panelDimension, clipedWidth, clipedHeight);
    }

    public BufferedImage getResizedCopyOfImage(BufferedImage originalImage,int scaledWidth, int scaledHeight, boolean preserveAlpha)
    {
        int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
        BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
        Graphics2D g = scaledBI.createGraphics();
        if (preserveAlpha)
        {
                g.setComposite(AlphaComposite.Src);
        }
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_RENDERING,
        RenderingHints.VALUE_RENDER_QUALITY);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
        g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
        g.dispose();
        return scaledBI;
    }

    public byte[] getByteOfImage(BufferedImage sourceImage)
    {
        try
        {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(sourceImage, getImageExtension(), baos);
            baos.flush();
            byte[] imageData = baos.toByteArray();
            baos.close();
            return imageData;
        }
        catch (IOException ex)
        {
            Exceptions.printStackTrace(ex);
            return null;
        }
    }

    public ImageIcon getImageIconFromImage(BufferedImage sourceImage)
    {
        return new ImageIcon(sourceImage);
    }

    public BufferedImage  getCropedImageOfImage(BufferedImage sourceImage, int x, int y, int width, int height)
    {
        return sourceImage.getSubimage(x, y, width, height);
    }
    public BufferedImage getCropedImageOfImageFromCenter(BufferedImage sourceImage, Dimension panelDimension,int clipedWidth, int clipedHeight)
    {
        Rectangle clip = new Rectangle(clipedWidth, clipedHeight);
        clip.x = (panelDimension.width - clip.width) / 2;
        clip.y = (panelDimension.height - clip.height) / 2;
        int x0 = (panelDimension.width - sourceImage.getWidth()) / 2;
        int y0 = (panelDimension.height - sourceImage.getHeight()) / 2;
        int x = clip.x - x0;
        int y = clip.y - y0;
        return sourceImage.getSubimage(x, y, clip.width, clip.height);
    }
}

Entity Inheritance Using Abstract Entity

In my previous blog I shared my code re-factoring experience by using Mapped Superclass. Using Abstract Entity was another interesting experience. In our project there are some Entities like Customer, Vendor which have some common attributes like 'First Name', 'Last Name', etc. These attributes were defined  in both Customer and Vendor Class. This approach not only produced code duplication but also column duplication in underlying Datastore. JPA Abstract Entity feature inspires me to use a third Entity Class which is abstract to avoid this duplication.

Let's see how it works. Suppose you have two Entities Student and Teacher, and they have following attributes



Three attributes are common in this case and you can introduce a Person class which is abstract and has these common properties. Student and Teacher class will extend Person and only have their individual properties.

Your  Person, Student and Teacher Entity classes will be like this

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name = "persons")
public abstract class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id_nr")
    protected Long idNr;
    @Column(name = "first_name")
    protected String firstName;
    @Column(name = "last_name")
    protected String lastName;
    
    public Person() {
    } 
    //getter setter of the properties ....


@Entity
@Table(name = "teachers")
public class Teacher extends Person {
    private static final long serialVersionUID = 1L;
    @Column(name = "designation")
    protected String designation;
    // constructor, getter setter of the property....


@Entity
@Table(name = "students")
public class Student extends Person {
    private static final long serialVersionUID = 1L;
    @Column(name = "role_number")
    protected String roleNumber;
    // constructor, getter setter of the property.... 

For above scenario three tables will be generated in the database, persons, students and teachers. Mapping strategy of @Inheritance annotation has a great impact in table generation process. As we have used InheritanceType.JOINED as the mapping strategy, three different tables are created. If we were using default mapping strategy which is InheritanceType.SINGLE_TABLE, only persons table will be created with all the attributes. In both cases Persistence provider will also create a discriminator column in the person table called DTYPE, which will store the name of the inherited entity used to create the person.

Now run the following code and see how data is stored in the database in this design.

        @PersistenceContext(unitName = "TaskBoard-ejbPU")
        EntityManager em;

        Teacher teacher = new Teacher();
        teacher.setFirstName("Sarwar");
        teacher.setLastName("Hossain");
        teacher.setDesignation("Associate Proffessor");
        teacher.setIdNr(null);
        em.persist(teacher);
        
        Student student = new Student();
        student.setFirstName("Shams");
        student.setLastName("Zawoad");
        student.setRoleNumber("001525");
        student.setIdNr(null);
        em.persist(student);
        em.flush();



If you try with InheritanceType.SINGLE_TABLE mapping strategy you will get the following output by running the same code

Attractive feature of abstract entities is that they can be queried just like concrete queries, which were not possible in Mapped Superclass. If an abstract entity is the target of a query, the query operates on all the concrete subclasses of the abstract entity.

Entity Inheritance Using Mapped Superclass

When I engaged myself into code re-factoring of our VELACORE project, I found that almost all Entities have four common properties createdBy, creationDate, modifiedBy and modificationDate.  I wanted to reduce this code duplication and found that JPA is providing Mapped Superclass for this type of requirement where state and mapping information are common to multiple Entity classes. It contains persistent state and mapping information, but is not Entitity. That is, it is not decorated with the @Entity annotation and is not mapped as an entity by JPA.

Mapped Superclasses do not have any corresponding tables in the underlying Datastore (that was also my requirement). Entities that inherit from the mapped Superclass define the table mappings. Mapped superclasses are specified by decorating the class with the javax.persistence.MappedSuperclass annotation.

Here is an example of using Mapped Superclass for entity inheritance

@MappedSuperclass
public class BaseEntity
{
    @Column(name = "created_by")
    private String createdBy;
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "creation_date")
    private Calendar creationDate;
    
   //getter setter of the properties ....
}

@Entity
public class Customer extends BaseEntity 
{
    @Column(name = "first_name")
    private String firstName;

    ...
}

@Entity
public class Invoice extends BaseEntity {
    @Column(name = "invoice_no")
    private String invoiceNo;

    ...
}


In the above code snippet BaseEntity is the MappedSuperclass which contains the mapping information of the common properties. Customer and Invoice are two Entities extending the BaseEntity. In this scenario only CUSTOMER and INVOICE tables will be created in the database not the BASEENTITY. "created_by" and "creation_date" columns will be present in both CUSTOMER and INVOICE tables.


Limitations of using Mapped Superclass :
-Mapped Superclasses are not queryable, and can’t be used in EntityManager or Query operations.
-Mapped Superclasses can’t be targets of entity relationships.

Total Pageviews

Tags

Twitter Updates
    follow me on Twitter

    Followers