esmaspäev, 11. mai 2015

Java & APNS

It might seem to be very painful at first but it's pretty simple at the end...

We'll need some Java APNS library (for example https://github.com/notnoop/java-apns )

Generate new certificate for APNS in iOS developer center. Then download it and import certificate into your KeyChain on Mac OS X.

From KeyChain (on MaxOS X), find certificate and private key. Select and export BOTH of them as *.p12 file.

Use them with your code as simple as:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//snippet of code used for testing puposes
String certificate = "certificates/ServerCertificateProd2015.p12";Mode mode = Mode.PRODUCTION;

byte[] bytes = IOUtils.toByteArray(Connection.class.getClassLoader().getResourceAsStream(certificate));

String password = "Your P12 Password";

ApnsServiceBuilder apnsServiceBuilder = APNS
    .newService()
    .withCert(new ByteArrayInputStream(bytes), password);

if(mode == Mode.DEVELOPMENT) {
    apnsServiceBuilder.withSandboxDestination();
} else {
    apnsServiceBuilder.withProductionDestination();
}

ApnsService apnsService = apnsServiceBuilder.build();

PayloadBuilder payloadBuilder = APNS.newPayload();
payloadBuilder.badge(1).alertBody("Hello");
String builtApns = payloadBuilder.build();
apnsService.push("YOUR_DEVICE_TOKEN", builtApns);

pühapäev, 8. märts 2015

Hibernate - equals and hashCode pitfails.

Hibernate uses proxies in order to load lazy dependencies.

And one of the common pitfails for me was to be so naive to implement equals()/hashCode() methods in following way:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Person that = (Person) o;

    if (id != null ? !id.equals(that.id) : that.id != null) return false;

    return true;
}

@Override
public int hashCode() {
    return id != null ? id.hashCode() : 0;
}


This code at least has two problems.

First.
It doesn't take in order that lazy loaded classes won't be of Person class. They will be of some Proxy-Generated class that is inherited from Person class.

Second.
Because returned instance is a proxy, not actual class, all of it's values will be null's or default values for primitive types. And the only valid way to interact with proxies is use accessor methods instead of direct field access.


So the proper implementation of equals(Object o)/hashCode() would be:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Person)) return false;

    Person that = (Person) o;

    if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;

    return true;
}

@Override
public int hashCode() {
    return getId() != null ? getId().hashCode() : 0;
}