Donnerstag, 19. April 2018

Remove ns2 in default namespace - JAXB, Entity XML Mapping

Just create a package-info.java file for your package in which you have your POJO:

@javax.xml.bind.annotation.XmlSchema(namespace = "http://myNameSpace", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package my.package;


The ns2 will be gone when you perform the usual Entity.xml(...)

Mittwoch, 18. April 2018

Generate JAXB Java Classes from XSD File

This is a fine one: if you only do have XML and nothing else, you can generate an XSD from the XML (here) and use the XSD to generate your Java POJOS.

I am currently forced to use windows, so I will use this example.

Download jaxb-ri-2.3.0 (Version may differ for you, what ever is the newest version).
Open CMD window and change to the directory  jaxb-ri-2.3.0\jaxb-ri\bin
Copy your XSD into the folder and type:
xjc.bat <yourfile.xsd> -d <yourDirectory>

And your POJOs will be generated, ready to use.

Dienstag, 27. März 2018

JAXB simplified JSON mapping + Rendering - How to parse Jaxb Response into POJO Java Class


How to parse Jaxb Response into POJO class:


Old:
//no POJO, but normal Response which still needs parsing…
Response response = service.request().accept(...).header(...)
                 .post(Entity.entity(myPojo, MediaType.APPLICATION_JSON_TYPE.withCharset("UTF-8")));

New:
// POJO, which can immediately be used…        
MyPOJOClass responsePojo = service.request().accept(...).header(...)
                 .post(Entity.json(myPojo), MyPOJOClass.class);


How to convert POJO to JAXB JSON Entity:


Old:
Entity.entity(myPojo, MediaType.APPLICATION_JSON_TYPE.withCharset("UTF-8"))

New:
Entity.json(myPojo)


 

How to print JSON request and response body in JAXB

Write a Filter for the Logging. Do not forget to annotate and register it:

import javax.ws.rs.client.Client;

client.register(new EntityLoggingFilter());


Filter Class:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.logging.Logger;

import javax.annotation.Priority;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;

@Priority(Integer.MIN_VALUE)
@Provider
public class EntityLoggingFilter implements ClientRequestFilter, ClientResponseFilter, WriterInterceptor {

    private static final Logger logger = Logger.getLogger(EntityLoggingFilter.class.getName());
    private static final String ENTITY_STREAM_PROPERTY = "EntityLoggingFilter.entityStream";
    private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
    private final int maxEntitySize = 1024 * 8;

    private void log(StringBuilder sb) {
        logger.info(sb.toString());
    }

    private InputStream logInboundEntity(final StringBuilder b, InputStream stream, final Charset charset) throws IOException {
        if (!stream.markSupported()) {
            stream = new BufferedInputStream(stream);
        }
        stream.mark(maxEntitySize + 1);
        final byte[] entity = new byte[maxEntitySize + 1];
        final int entitySize = stream.read(entity);
        b.append(new String(entity, 0, Math.min(entitySize, maxEntitySize), charset));
        if (entitySize > maxEntitySize) {
            b.append("...more...");
        }
        b.append('\n');
        stream.reset();
        return stream;
    }

    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        if (requestContext.hasEntity()) {
            final OutputStream stream = new LoggingStream(requestContext.getEntityStream());
            requestContext.setEntityStream(stream);
            requestContext.setProperty(ENTITY_STREAM_PROPERTY, stream);
        }
    }

    @Override
    public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
        final StringBuilder sb = new StringBuilder();
        if (responseContext.hasEntity()) {
            responseContext.setEntityStream(logInboundEntity(sb, responseContext.getEntityStream(), DEFAULT_CHARSET));
            log(sb);
        }

    }

    @Override
    public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
        final LoggingStream stream = (LoggingStream) context.getProperty(ENTITY_STREAM_PROPERTY);
        context.proceed();
        if (stream != null) {
            log(stream.getStringBuilder(DEFAULT_CHARSET));
        }
    }

    private class LoggingStream extends FilterOutputStream {

        private final StringBuilder sb = new StringBuilder();
        private final ByteArrayOutputStream baos = new ByteArrayOutputStream();

        LoggingStream(OutputStream out) {
            super(out);
        }

        StringBuilder getStringBuilder(Charset charset) {
            // write entity to the builder
            final byte[] entity = baos.toByteArray();

            sb.append(new String(entity, 0, entity.length, charset));
            if (entity.length > maxEntitySize) {
                sb.append("...more...");
            }
            sb.append('\n');

            return sb;
        }

        @Override
        public void write(final int i) throws IOException {
            if (baos.size() <= maxEntitySize) {
                baos.write(i);
            }
            out.write(i);
        }
    }
}

Mittwoch, 21. März 2018

How to map a java.util.Date to a specific JSON java.lang.String - Date Serialization with Jackson 2.8.4

I do prefer Jackson for serializing and deserializing from and to JSON.

For Date to String conversion you do only need one simple annotation:


import com.fasterxml.jackson.annotation.JsonFormat;

// "2018-03-02T12:00:00";
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyy-MM-dd'T'HH:mm:ss")
public Date TimeStamp;

Dienstag, 20. März 2018

On Testing, Databases and Testdata - TDD Success Story

I was on-site at a large software company, reknown and with a ton of reputation. They are doing things with your money, you know. So they have to be secure.

Now, there was a habit there, to use live data for testing. Something which is sometimes done.
Anyway, they claimed that, because it was live-data they were testing with, it was a very good thing to use live-data and because every second day there would be an update of data from the live database to the test database, everything would be up-to-date. Good idea. You might think.

And then, after three months of development, it happened.
A customer dared - yes I use the word DARED by intention to point out the irony - he dared to use the core feature of the the software, which was to create or change price models.

There were not ten price models. Not a hundred. There were a thousand price models. Something in that range. And the customer decided to change about 90% of them. Yes.

The very next morning, the data had already been cloned into the dev database.
Because the administrators are unfortunately overwhelmed by the amounts of data they are dealing with, they do not manage to perform a rollback.

Prior to the next release, which was planned for the next day, they were admittedly unable to do a rollback. The testers, experienced guys, external employees like I, said in the emergency meeting that the software cannot be reliably tested.

That was it. To cancel the release would have meant breeching contractual agreements with at least two of the largest customers. What could we do?

2 months before I had a personal interview with the Head of Development, a good guy with profound knowledge who is suffering from a constant lack of resources (by saying resources the company means actual human employees, just to make it clear). He instructed me NOT to write too many UNIT tests. Because this would only slow down the development which is under constant pressure from the business side because it performs at a pace being considered too slow for the mega advanced Management. So omitting the Tests would speed it up. So he said.

Needless to say that I ignored it. I wrote tests for the most important functions, basically a lot of math for financial calculation. UNIT based, independent from the database. Maybe the Head of Dev would have cancelled our contract if he would have known at the time. But I knew that arguing would not make a difference for a person being under such pressure. The team had tried before and been ignored.

Now, when we had this emergency meeting, I said: "We can do the release."
Eyes stared at me with the expression of a panicking animal. "What?"
I said: "We can because I have UNIT tests for all your business functions."
"What?"
"Yes. Calculation is correct. Let's do the release."

The release was done and everything went pretty smoothly.

A few days after, the Head of Dev approached me by saying that doing UNIT Tests for the business critical parts of the software would be a very good thing and encouraged the whole team to establish this technique from now on. Really true.

I even managed to introduce them to Pair Programming, my favorite XP technique besides TDD, but that is another story, eh, post.

All the best,
Tim












Freitag, 16. März 2018

Online Tutorials, Generation Tools for Basic Auth + JSON

Hi there,

I found a nice and simple authentication header generator for Basic Authentication:
https://www.blitter.se/utils/basic-authentication-header-generator/

Probably the best JSON formatter online (pretty-print), nice for analysis:
https://jsonformatter.curiousconcept.com/

Both useful for doing ad-hoc requests, maybe with
Advanced Rest Client: https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

Last but not least a nice collection of mini tutorials. Focused on practicality:
http://www.mkyong.com/all-tutorials-on-mkyong-com/

Best,
Tim 

Freitag, 9. März 2018

Harder IT Consulting - JAVA für Hamburg. Ab Juni 2018!

Liebe Leser,

ab Juni 2018 geht es los. Als IT Consultant bin ich für Rollen in den Bereichen Architektur, Design und Coaching buchbar.

Harder IT Consulting ist meine dritte Firma (die erste habe ich verkauft, die zweite ist eine reine Produktlinie, die dritte ist Harder IT Consulting).

Dort, wo Kompetenzen für Java oder komplexe Software Architekturen und vertrackte Probleme in diesen gelöst werden müssen, sieht man mich häufig.


Der Feuerwehrmann sucht immer den Brandherd.

  • Haben Sie zuwenig Entwickler?
  • Sind Ihre Teams überlastet?
  • Haben Sie Probleme mit einer vertrackten Softwarelandschaft?
  • Brauchen Sie Software-Kompetenz mit Erfahrung?

Zufriedene Kunden sind unter anderem:
Kühne + Nagel, BMW, U.S. Navy, EOS, Universal, Vodafone, O2...

Schreiben Sie, rufen Sie an, ich freue mich.

Freundliche Grüße aus Hamburg Bergedorf,

 Tim Harder
- Inhaber -

HARDER IT CONSULTING
Tim Harder - Inhaber

Fanny-Lewald-Ring 128
21035 Hamburg

Mobil: +49 172 4289053
Mail: tim@harder-it-consulting.de   -   Web: www.harder-it-consulting.de

XING LinkedIn

Blog: GOOD NEWS FROM THE IT CROWDhttps://harderconsulting.blogspot.de/





<a href="https://www.freelancermap.de/freelancer-verzeichnis/profile/entwicklung/142866-profil-tim-harder-harder-it-consulting-inhaber-consultant-entwickler-architekt-buchbar-ab-juni-2018-aus-hamburg.html" target="_blank" title="Profil von Tim Harder auf www.freelancermap.de"><img src="https://www.freelancermap.de/images/widgets/button/findenSieMich.png"></a>

Dienstag, 27. Februar 2018

Rechnen mit Java in der Finanzwelt (German)

Nach vielen Jahren in der IT Crowd wurde es Zeit für einen eigenen Blog.
Was mir als IT Consultant so alles an nützlichen und skurrilen Dingen über den Weg läuft, halte ich hier fest.

In unzähligen Fällen, in denen Firmen Geld verloren ging oder zuviel auftauchte, stellte ich fest - das muss nicht immer mit den Panzerknackern zu tun haben. Programmiersprachen erledigen das ganz von selbst - gesetzt des Falles, dass sie nicht richtig angewandt werden.

Im nachfolgenden Beispiel, stelle ich dar, wie einem realen Unternehmen Fehlrechnungen unterliefen, die sie sich zunächst nicht erklären konnten.

Natürlich werden weder Namen, noch Zeit und Ort genannt. Der Fall könnte gestern passiert sein oder vor 5 Jahren - das soll keine Rolle spielen. Geschäftsdetails sind nicht enthalten und ich habe den Fall mit einem privaten Beispiel nachgestellt.

Viel Spaß beim Lesen.

P.S.
Solche Sachen werden gelegentlich verfilmt. Wer mal sehen will, wie ich und meinesgleichen so leben und was sie alles erdulden müssen, sollte sich diesen Film ansehen:

Alles Routine (DE)


Rechnen mit Java in der Finanzwelt

von: Tim Harder
Immer wieder stellt man bei der Sichtung von Software fest, dass das Rechnen in Java zu Problemen führt, wenn primitive Datentypen verwendet werden.
Hier ein aktuelles Beispiel eines Rundungsfehlers, bei einem Finanz Dienstleister, der beliebig hohe Summen zuviel oder zuwenig berechnet, ohne, dass es gleich auffällt:
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
// GIVEN
 
final Integer price = -595;
 
final Integer someUnit = 90;
 
{
 
// WHEN
 
int multiplicationResult = price * someUnit;
 
// = -53550
 
Integer resultAmount = multiplicationResult / 100;
 
// = -535
 
// …Division fehlgeschlagen,
 
// Nachkommastellen ignoriert...
 
// THEN
 
assertTrue(resultAmount == -535);
 
// Falsch. Es müsste -536 sein.
 
}
…und was passiert, wenn man mit Datentypen rechnet, die Zahlenräume korrekt abbilden können:

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
// GIVEN
 
final Integer price = -595;
 
final Integer someUnit = 90;
 
{
 
// WHEN
 
BigDecimal priceBD = new BigDecimal(price);
 
BigDecimal someUnitBD = new BigDecimal(someUnit);
 
BigDecimal hundred = new BigDecimal(100);
 
BigDecimal multiplicationResult = priceBD.multiply(someUnitBD); // = -53550
 
// = -535.5 bedeutet, alles sieht gut aus
 
BigDecimal resultAmountBD = multiplicationResult.divide(hundred);
 
final int noDecimalPlaces = 0;
 
// rounding mode essentiell für das Ergebnis
 
final RoundingMode roundingMode = RoundingMode.HALF_UP;
 
// Nachkommastellen definieren
 
BigDecimal result = resultAmountBD.setScale(noDecimalPlaces, roundingMode);
 
// THEN
 
assertThat(result.toBigInteger().intValue(), equalTo(-536)); // Richtig!
 
}


Warum ist das so?
Laut Standard IEEE 754 wird für Exception Handling und Zahlenräume definiert, wie float und double rechnen.
Floating Points sind dafür geeignet, Annäherungen zu beschreiben, schnell, aber ohne die für ein exaktes Resultat notwendige Präzision.
BigDecimal arbeitet intern mit String Repräsentationen und arbeitet sich Stück für Stück vor, weshalb dieser Datentyp zum einen unabhängiger von definierten, sprich begrenzten Zahlenräumen ist.
Außerdem kann die Präzision der Berechnung genauestens definiert werden.
Das ermöglicht die Erstellung von Kontrakten zum Thema Berechnung: Wird aufgerundet, oder abgerundet? Wieviele Nachkommastellen? Welche Darstellung im System?
So haben Banken in den meisten Fällen den „Bank Rounding Mode“. Alle Systeme, die miteinander im Kontext eines Anwendungsfalles sprechen, einigen sich auf diese Form der Berechnung.
 
Warum ist das so wichtig?
In einem aktuellen Fall nimmt ein System innerhalb eines Kontexts nur zwei Nachkommastellen an.
Es berechnet daraus Summen und schickt diese zurück. Dadurch entsteht eine Differenz zwischen den Eingangswerten und darauf basierenden Annahmen und den zusätzlichen Ergebnissen aus diesem System. Das System ist eine Blackbox und es kann nicht mehr festgestellt werden, was genau dort berechnet wurde. Hätte man von vornherein einen Kontrakt definiert, der nicht nur die Präzision der Nachkommastellen, sondern auch die Rundungs Modi definiert, rechneten alle Systeme gleich.
So etwas führt mitunter zu beliebig hohen Summen, die akkumuliert zuviel oder zuwenig berechnet werden und welche nachher buchhalterisch zu Verlusten führen, da man mit Geld hantiert, welches es genau genommen gar nicht gibt.

NEW BLOG! http://cleancode.consulting/

Dear Reader, This Blog is closed and remains as an archive. Please find our new Blog at  http://cleancode.consulting/