Donnerstag, 28. Juli 2016

Java equals() hashCode() methods and how to deal with it?

Long story short ...

if there are two objects to compare against each other (no matter used by standard Java libraries in background or by themeselves) the object1.equals(object2) method should be used.

Why or when should equals() be overriden?

An object.equals() method should be overriden, i.e. if there is a single ID attribute, a combination of attributes or something else which should equals, ALTHOUGH memory addresses of two object differs.

Usually the memory addresses will be compared (with help of the object.hashCode() method). That means if you create two independent objects (with new()) of the same class with the same attributevalues those objects won't be equal. So you have to decide, are two objects equal by their attributes or by their adresses.

Why or when should hashCode() be overriden?

The method hashCode() should always be overriden when equals() will be overriden!
To give you a better example with output result work through the code listing below.

Code example

package tutorial;

public class HashCodeEqualsTutorial {

int id;
String text;

HashCodeEqualsTutorial(int id, String text) {
this.id = id;
this.text = text;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getText() {
return text;
}

public void setText(String text) {
this.text = text;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((text == null) ? 0 : text.hashCode());
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
HashCodeEqualsTutorial other = (HashCodeEqualsTutorial) obj;
if (id != other.id) return false;
if (text == null) {
if (other.text != null) return false;
} else if (!text.equals(other.text)) return false;
return true;
}

@Override
public String toString() {
return this.getClass().getName() + " [id=" + id + ", text=" + text + " hashCode=" + this.hashCode() + "]\n";
}

static String reportIfEquals(HashCodeEqualsTutorial obj1, HashCodeEqualsTutorial obj2) {
if (obj1.equals(obj2))
{
return " = "
+ obj1.toString()
+ "\n = "
+ obj2.toString();
} else {
return "<> "
+ obj1.toString()
+ "\n<> "
+ obj2.toString();
}
}

public static void main(String[] args) {
HashCodeEqualsTutorial obj1 = new HashCodeEqualsTutorial(1, "ABC");
HashCodeEqualsTutorial obj2 = new HashCodeEqualsTutorial(1, "ABC");

System.out.println(reportIfEquals(obj1, obj2));

obj2.setText("DEF");
System.out.println(reportIfEquals(obj1, obj2));

obj2.setId(2);
System.out.println(reportIfEquals(obj1, obj2));

obj2.setText(obj1.getText());
obj2.setId(obj1.getId());
System.out.println(reportIfEquals(obj1, obj2));
}
}

/* https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html
 * 2016-07-28
 *  
...
The equals() Method

The equals() method compares two objects for equality and returns true if they are equal. The equals() method provided in the Object class uses the identity operator (==) to determine whether two objects are equal. For primitive data types, this gives the correct result. For objects, however, it does not. The equals() method provided by Object tests whether the object references are equal—that is, if the objects compared are the exact same object.

To test whether two objects are equal in the sense of equivalency (containing the same information), you must override the equals() method. Here is an example of a Book class that overrides equals():

public class Book {
   ...
   public boolean equals(Object obj) {
       if (obj instanceof Book)
           return ISBN.equals((Book)obj.getISBN()); 
       else
           return false;
   }
}

Consider this code that tests two instances of the Book class for equality:

// Swing Tutorial, 2nd edition
Book firstBook  = new Book("0201914670");
Book secondBook = new Book("0201914670");
if (firstBook.equals(secondBook)) {
   System.out.println("objects are equal");
} else {
   System.out.println("objects are not equal");
}
This program displays objects are equal even though firstBook and secondBook reference two distinct objects. They are considered equal because the objects compared contain the same ISBN number.

You should always override the equals() method if the identity operator is not appropriate for your class.

Note: If you override equals(), you must override hashCode() as well.
...

...
The hashCode() Method

The value returned by hashCode() is the object's hash code, which is the object's memory address in hexadecimal.

By definition, if two objects are equal, their hash code must also be equal. If you override the equals() method, you change the way two objects are equated and Object's implementation of hashCode() is no longer valid. Therefore, if you override the equals() method, you must also override the hashCode() method as well.

The toString() Method

You should always consider overriding the toString() method in your classes.

The Object's toString() method returns a String representation of the object, which is very useful for debugging. The String representation for an object depends entirely on the object, which is why you need to override toString() in your classes.

You can use toString() along with System.out.println() to display a text representation of an object, such as an instance of Book:

System.out.println(firstBook.toString());
which would, for a properly overridden toString() method, print something useful, like this:

ISBN: 0201914670; The Swing Tutorial; A Guide to Constructing GUIs, 2nd Edition
« Previous • Trail • Next »
Your use of this page and all the material on pages under "The Java Tutorials" banner is subject to these legal notices.

Copyright © 1995, 2015 Oracle and/or its affiliates. All rights reserved.
...
 */

Code result

As output result (hashCode number will be different to yours).:


 = tutorial.HashCodeEqualsTutorial [id=1, text=ABC hashCode=65570]
 = tutorial.HashCodeEqualsTutorial [id=1, text=ABC hashCode=65570]

<> tutorial.HashCodeEqualsTutorial [id=1, text=ABC hashCode=65570]
<> tutorial.HashCodeEqualsTutorial [id=1, text=DEF hashCode=68549]

<> tutorial.HashCodeEqualsTutorial [id=1, text=ABC hashCode=65570]
<> tutorial.HashCodeEqualsTutorial [id=2, text=DEF hashCode=68580]

 = tutorial.HashCodeEqualsTutorial [id=1, text=ABC hashCode=65570]
 = tutorial.HashCodeEqualsTutorial [id=1, text=ABC hashCode=65570]

Sonntag, 6. Dezember 2015

Programming rectangle with C++

Goal

I just wanted to create a simple triangle and moving it around with the arrow keys on keyboard.
The boarders are set around the rectangle and stops moving if boarders are close to the rectangle frame.
Curious about the input issues I got. Imagine a word document and keep holding a key. As result you get the pressed key immadiately a short break and a series of elements pretty fast till the key is released. The same effect was here with the recommenden key_callback() function from GLFW here Receiving input events while moving the rectangle around. It stopped always a while while holding an arrow key pressed.
A good solution for this issue was to poll the events with glfwPollEvents() but is less convinient (the hard way) to check the current state of the defined keys.

Requirements

Codeblocks 13.12 + Mingw
GLFW 3.1.2
OpenGL 2.1 (old fashion OpenGL, some functions are already deprecated but working on most plattforms)

Sourcecodes

#ifndef GAME2D_H_INCLUDED
#define GAME2D_H_INCLUDED

#include
#include
#include

// SETUP DATE ------------------
const float citDelta       = 0.0125f;
const float citRectLength  = 1.0f / 3.0f;
const float citRectHeight  = 0.04;
// ------------------ SETUP DATE

//void character_callback(GLFWwindow* window, unsigned int codepoint);
void citX(float& x);
void citY(float& y);
int  citRun();

/*************************************************************************************************************
* diffclock() (c) Satbir Oct 4 '09 at 15:40                                                                  *
* http://stackoverflow.com/questions/1516659/how-do-i-count-how-many-milliseconds-it-takes-my-program-to-run *
*************************************************************************************************************/
double diffclock(clock_t clock1,clock_t clock2);

#endif // GAME2D_H_INCLUDED

Listing: Game2d.hpp
_____________________
#include "Game2d.hpp"

int main()
{
    return citRun();
}

Listing: main.cpp
_____________________
#include "Game2d.hpp"

#include "Game2d.hpp"

using namespace std;

static void error_callback(int error, const char* description)
{
    cerr << "ERROR DESCRIPTION [" << description << "]";
}

int citRun()
{
    GLFWwindow* window;

    float       ratio;
    int         height;
    int         width;

    float       x               = 0;
    float       y               = 0;

    int         cit_KEY_DOWN;
    int         cit_KEY_LEFT;
    int         cit_KEY_RIGHT;
    int         cit_KEY_UP;
    int         cit_LAST_LEFT_RIGHT = 0;
    int         cit_LAST_UP_DOWN    = 0;

    // init ---------------------------------------------
    glfwSetErrorCallback(error_callback);

    if (!glfwInit())
        return -1;

    window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);

    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);
    //glfwSetCharCallback(window, character_callback);
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
    // --------------------------------------------- init

    // main loop ----------------------------------------
    while (!glfwWindowShouldClose(window))
    {
        glfwGetFramebufferSize(window, &width, &height);
        ratio = (float) width / (float) height;
        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        // --- handle key input -----------------------------
        glfwPollEvents();

        cit_KEY_LEFT    = glfwGetKey(window, GLFW_KEY_LEFT);
        cit_KEY_RIGHT   = glfwGetKey(window, GLFW_KEY_RIGHT);
        cit_KEY_UP      = glfwGetKey(window, GLFW_KEY_UP);
        cit_KEY_DOWN    = glfwGetKey(window, GLFW_KEY_DOWN);

        if (cit_KEY_LEFT == GLFW_PRESS && cit_KEY_RIGHT != GLFW_PRESS)
            cit_LAST_LEFT_RIGHT = GLFW_KEY_LEFT;

        if (cit_KEY_LEFT != GLFW_PRESS && cit_KEY_RIGHT == GLFW_PRESS)
            cit_LAST_LEFT_RIGHT = GLFW_KEY_RIGHT;

        if (cit_KEY_LEFT != GLFW_PRESS && cit_KEY_RIGHT != GLFW_PRESS)
            cit_LAST_LEFT_RIGHT = 0;

        if (cit_KEY_UP == GLFW_PRESS && cit_KEY_DOWN != GLFW_PRESS)
            cit_LAST_UP_DOWN = GLFW_KEY_UP;

        if (cit_KEY_UP != GLFW_PRESS && cit_KEY_DOWN == GLFW_PRESS)
            cit_LAST_UP_DOWN = GLFW_KEY_DOWN;

        if (cit_KEY_UP != GLFW_PRESS && cit_KEY_DOWN != GLFW_PRESS)
            cit_LAST_UP_DOWN = 0;

        // --- debug code --------------------------------------
        //if (cit_KEY_LEFT  == GLFW_PRESS
        //||  cit_KEY_RIGHT == GLFW_PRESS
        //||  cit_KEY_UP    == GLFW_PRESS
        //||  cit_KEY_DOWN  == GLFW_PRESS)
        //{
        //    cout << "["  << x << "|" << y << "]" << endl;
        //    cout << "cit_KEY_LEFT  =["  << (cit_KEY_LEFT  == GLFW_PRESS ? "true" : "false") << "]" << endl;
        //    cout << "cit_KEY_RIGHT =["  << (cit_KEY_RIGHT == GLFW_PRESS ? "true" : "false") << "]" << endl;
        //    cout << "cit_KEY_UP    =["  << (cit_KEY_UP    == GLFW_PRESS ? "true" : "false") << "]" << endl;
        //    cout << "cit_KEY_DOWN  =["  << (cit_KEY_DOWN  == GLFW_PRESS ? "true" : "false") << "]" << endl;
        //}
        // --- debug code -----------------------------------

        if (cit_LAST_LEFT_RIGHT == GLFW_KEY_LEFT)
        {
            x -= citDelta;
        }

        if (cit_LAST_LEFT_RIGHT == GLFW_KEY_RIGHT)
        {
            x += citDelta;
        }

        if (cit_LAST_UP_DOWN == GLFW_KEY_UP)
        {
            y += citDelta;
        }

        if (cit_LAST_UP_DOWN == GLFW_KEY_DOWN)
        {
            y -= citDelta;
        }

        if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
            glfwSetWindowShouldClose(window, GL_TRUE);

        citX(x);
        citY(y);
        // --- handle key input -----------------------------

        // --- handle graphic output ------------------------
        glBegin(GL_LINE_STRIP);
          glVertex3f(x - citRectLength/2, y - citRectHeight/2, 0.0f);
          glVertex3f(x - citRectLength/2, y + citRectHeight/2, 0.0f);
          glVertex3f(x + citRectLength/2, y + citRectHeight/2, 0.0f);
          glVertex3f(x + citRectLength/2, y - citRectHeight/2, 0.0f);
          glVertex3f(x - citRectLength/2, y - citRectHeight/2, 0.0f);
        glEnd();
        // --- handle graphic output ------------------------

        glfwSwapBuffers(window);
    }
    // ---------------------------------------- main loop

    // close app ----------------------------------------
    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
    // ---------------------------------------- close app
}

void citX(float &x)
{
    if (x >  1 + citRectLength/2)
        x =  1 + citRectLength/2;
    else
    if (x < -1 - citRectLength/2)
        x = -1 - citRectLength/2;
}

void citY(float &y)
{
    if (y >  1 - citRectHeight/2)
        y =  1 - citRectHeight/2;
    else
    if (y < -1 + citRectHeight/2)
        y = -1 + citRectHeight/2;
}

/*************************************************************************************************************
* diffclock() (C) Satbir Oct 4 '09 at 15:40                                                                  *
* http://stackoverflow.com/questions/1516659/how-do-i-count-how-many-milliseconds-it-takes-my-program-to-run *
*************************************************************************************************************/
double diffclock(clock_t clock1,clock_t clock2)
{
    double diffticks=clock1-clock2;
    double diffms=(diffticks)/(CLOCKS_PER_SEC/1000);
    return diffms;

}

Listing: Game2d.cpp

Download project

Mittwoch, 28. Oktober 2015

OpenGL with Codeblocks + MinGW + GLEW + GLFW3

This is an installation manual for modern OpenGL tools. Modern refers espacially to GLFW3.

Codeblocks 13.12 (with MinGW compiler) GLEW 1.13.0 and GLFW 3.1.1. configuration running and compiling to an error free executeable on Windows 8 (32 bit)


Downloads


- Codeblocks 13.12 (with MinGW compiler) http://www.codeblocks.org/
- GLEW glew-1.13.0-win32.zip http://glew.sourceforge.net/ > Binaries Windows 32-bit and 64-bit
- GLFW glfw-3.1.1.bin.WIN32.zip http://glfw.org > Download > 32-bit Windows binaries

Codeblocks is installed with the wizard into the predefined directory.

Prepare


For GLEW and GLFW, two directories are created by hand. C:\include, C:\lib.

From glew-1.13.0-win32.zip glew-1.13.0\include\GL extract the GL directory to C:\include\GL.
Three files should be there.
- C:\include\GL\glew.h
- C:\include\GL\glxew.h
- C:\include\GL\wglew.h

Next extract C:\Users\Daniel\OneDrive\OpenGL\libraries\glew-1.13.0-win32.zip\glew-1.13.0\lib\Release\Win32 to C:\lib.
- C:\lib\glew32.lib
- C:\lib\glew32s.lib

GLEW libraries are available for forther use.

The similar steps are done with GLFW, glfw-3.1.1.bin.WIN32.zip\glfw-3.1.1.bin.WIN32\include\GLFW is gonna be extracted to
- C:\include\GLFW\glfw3.h
- C:\include\GLFW\glfw3native.h.

All files from glfw-3.1.1.bin.WIN32.zip\glfw-3.1.1.bin.WIN32\lib-mingw has to be extracted to
- C:\lib\glfw3.dll
- C:\lib\glfw3dll.a
- C:\lib\libglfw3.a

Additionaly the DLL files should be copied in the C:\Windows\System32 directory.
Maybe a restart of Windows might be necassary to ensure the files are loaded.
At least the DLLs should be in the same directory as the exeecutable files (*.exe).

Config


I assume the libraries should only be configured for each Codeblocks project and not for the whole Codeblocks environment.

Open Codeblocks and create a new console project with File > New > Project > Console projet > Go > Next > C++ > Next > Project title: OpenGLTest > Next > Finish.


Overwrite main.cpp to the below sourcecode [(C) http://www.learnopengl.com/code_viewer.php?code=getting-started/hellowindow2].

#include

// GLEW
#define GLEW_STATIC
#include

// GLFW
#include


// Function prototypes
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode);

// Window dimensions
const GLuint WIDTH = 800, HEIGHT = 600;

// The MAIN function, from here we start the application and run the game loop
int main()
{
    std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;
    // Init GLFW
    glfwInit();
    // Set all the required options for GLFW
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    
    // Create a GLFWwindow object that we can use for GLFW's functions
    GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "LearnOpenGL", nullptr, nullptr);
    
    if (window == nullptr)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }
    
    glfwMakeContextCurrent(window);
    // Set the required callback functions
    glfwSetKeyCallback(window, key_callback);
    
    // Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
    glewExperimental = GL_TRUE;
    // Initialize GLEW to setup the OpenGL Function pointers
    if (glewInit() != GLEW_OK)
    {
        std::cout << "Failed to initialize GLEW" << std::endl;
        return -1;
    }
    
    // Define the viewport dimensions
    glViewport(0, 0, WIDTH, HEIGHT);

    // Game loop
    while (!glfwWindowShouldClose(window))
    {
        // Check if any events have been activiated (key pressed, mouse moved etc.) and call corresponding response functions
        glfwPollEvents();

        // Render
        // Clear the colorbuffer
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Swap the screen buffers
        glfwSwapBuffers(window);
    }
    
    // Terminate GLFW, clearing any resources allocated by GLFW.
    glfwTerminate();
    return 0;
    }
    
// Is called whenever a key is pressed/released via GLFW
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode)
{
    std::cout << key << std::endl;
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

Go to Project > Build options... and point to the treenode OpenGL and the register Linker settings.

The order of the defined library files are important. Compiling might not work in a different order.

C:\lib\glew32s.lib
C:\lib\glew32.lib
C:\lib\glfw3dll.a
glfw3
opengl32
glu32
gdi32

In the register Search directory > Compiler > Add the C:\include directory must be added here.
In the register Search directory > Linker > Add the C:\lib directory must be added here.

Build and run demo application


Building with Build > Build should create the Build log below.

-------------- Build: Release in OpenGLTest_2 (compiler: GNU GCC Compiler)---------------

mingw32-g++.exe -Wall -fexceptions -O2 -std=c++0x -IC:\include -c C:\workspace\OpenGLTest\main.cpp -o obj\Release\main.o
mingw32-g++.exe -LC:\lib -o bin\Release\OpenGLTest.exe obj\Release\main.o -s C:\lib\glew32s.lib C:\lib\glew32.lib C:\lib\glfw3dll.a -lglfw3 -lopengl32 -lglu32 -lgdi32
Warning: .drectve `/DEFAULTLIB:"LIBCMT" /DEFAULTLIB:"OLDNAMES" ' unrecognized
Output file is bin\Release\OpenGLTest.exe with size 655.50 KB
Process terminated with status 0 (0 minute(s), 6 second(s))
0 error(s), 1 warning(s) (0 minute(s), 6 second(s))

Starting the demo application with Build > Run should show up a black and emoty window "LearnOpenGL". If so, everything went well so far. :)

I can recommend the ressource http://www.learnopengl.com/ for further material about OpenGL.

BR Daniel

Freitag, 28. August 2015

Dynamics AX - Native ODBC SMALLDATETIME update

Overview

Updating a SQL-SMALLDATETIME field with ODBC is far away from X++ code in Dynamics AX.


Issue

If a smalldatetime field should be set with ODBC the errorlog
"[Microsoft][ODBC SQL Server Driver][SQL Server] The conversion of char data type to smalldatetime data type resulted in an out-of-range smalldatetime value." can be thrown and stops further critical functionality.


Solution

A working solution to define the value in ISO 8601 is to use the capital letter T between DATE and TIME values.[1][2]

The format goes like this 'YYYY-MM-DDThh:mm:ss'.


Example

The exmple listing shows an ODBC-querystring.

str sqlUpdate = "UPDATE [DATABASE].[dbo].[TABLE]"
            +   " SET DATEFIELD = '2015-08-28T22:08:54'";

The string can be sent to the Statement.executeUpdate(updateSQL) classmethod to update the DATEFIELD (ODBCconnection class has to be set first). 


Sources:
[1] 28.08.2015 https://social.msdn.microsoft.com/Forums/sqlserver/en-US/42d5b895-3767-4775-a18e-21ac8485b37a/update-smalldatetime-column
[2] 28.08.2015 http://www.cl.cam.ac.uk/~mgk25/iso-time.html

Underline:
YYYY - year 4 dgits
MM - month 2 digits
DD - day 2 digits
hh - hour 2 digits
mm - minute 2 digits
ss - second 2 digits

Samstag, 11. Juli 2015

Date conversion in Java SE8

Date conversion between string-formats in Java SE 8

Requirements

Date conversion is in some cases nice to have for different countries and regions. It can also be a technical must have for database comparasion or storing content into date fields. Before Java SE8, there are many SimpleDateFormat examples outside. The following solution is oriented to SE8.
A basic requirement is to deal with string input and output to assign to JPA i.e.

The method should change a string from the example date "03.07.2014" to string "2014-07-03".

Solution

The script is a complete static solution to drag'n'drop into a new Java class. There are only basic operations and SE8 java.time.LocalDate and import java.time.format.DateTimeFormatter classes.

package DateConPackage;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class DateCon
{
    public static String value2QueryDate(String dateValue, 
                                         String inpattern, 
                                         String outpattern)
    {
        String              ret;
      
        DateTimeFormatter   dateFormatValue = 
                            DateTimeFormatter.ofPattern(inpattern);
        LocalDate           localDateValue  = 
                            LocalDate.parse(dateValue, dateFormatValue);

        ret =  localDateValue.format
               (
                    DateTimeFormatter.ofPattern(outpattern)
               );

        return ret;
    }
}


Script 1: DateCon.java


Example

In order to use it right, the date format has also to be considered. In most cases, day, month and year are fitting most cases. There are more detailed information for time and so on right here http://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

Date "03.07.2014" results to pattern "dd-MM-yyyy" and "2014-07-03" to "yyyy-MM-dd". The capital letters for month "MM" are mandatory.

package DateConPackage;


public class DateConExample
{
    public static void main(String[] args)
    {
        String fromdate = "03.07.2014";
        String todate   = "";
      
        todate = DateCon.value2QueryDate(fromdate,
                                         "dd.MM.yyyy",
                                         "yyyy-MM-dd");
      
        System.out.println(   "Inputdate: "
                            + fromdate
                            + " Outputdate: "
                            + todate);
    }

}

Script 2: DateConExample.java

Output

Running Script 2: DateConExample.java shows the result to the system output.

Inputdate: 03.07.2014 - Outputdate: 2014-07-03