JTraining Blog

Share your knowledge.
Tags >> Java SE
rpnman
rpnman

I've always had a pet peeve that introductory Java books teach developers the bad habit of using the static keyword and executing business logic code in the main method.  I believe this is done in part out of a misguided intention of avoiding confusion, but also out of laziness.

 I've seen lots of bugs and unmaintainable architectural choices (some subtle, some not)  introduced by overuse of static references and methods, and find myself wondering how much of this is attributable to the failure of Java teachers to make the distinction between class and object clearer from the outset. 

 I'm very pleased to see BlueJ (which I first learned of here on JTraining) as an effort to remedy this general failure in Java and OO programming training. 


Tagged in: Tutorial , tools , Testing , Teaching , Student , Netbeans , JTraining , Java SE , IDE , Eclipse
rpnman
rpnman

Java is a great programming language, but everyone who uses the term knows that it is much more than that. At a minimum, the term includes, the JVM, the API libraries (the language is almost useless without them.) Of course, in any practical application that includes so much more: frameworks, functional libraries, coding conventions, development infrastructure such as unit test and continuous build, and so on and so on.

 The gist of my post is that far beyond all these technical extensions to "Java" as a technical term, I tend to think of "Java" as a development and software engineering culture, and, for me, that culture implies an attitude of learning. The technology of the Java environment is evolving so quickly that learning is just plain part of the normal ongoing routine. 

Great developers are naturally part of great teams. Great teams are great in part because they allow their members to flourish and become great. A key element of that greatness, in my opinion and in my experience, depends on continuous, ongoing learning. 


svanhugten
svanhugten

De annotaties zijn al een tijdje ingeburgerd in Java en iedereen die ooit met Java 1.5 of hoger heeft gewerkt, zal het vertrouwde @-tje herkennen, maar hoe vaak heb je er nu een zelf gemaakt? Waarschijnlijk nooit, want dat is toch het domein van de Springs, Hibernates en andere frameworks in deze wereld. Hoe gaat het überhaupt in zijn werk? Het is namelijk geen onderdeel van een of ander certificaat.
Op internet zijn wel wat dingen te vinden over hoe annotaties te maken, maar daarbij valt me op dat er nooit wordt ingegaan op zogenaamde runtime annotaties, annotaties die je ook tijdens het runnen van jouw programma kunt gebruiken.

Annotaties zijn in feite niet meer dan interfaces:

public
@interface Ranked {
      String column() default "";
}

Er vallen wel een aantal dingen op; voor het keyword interface staat een @-tje en de property declaratie ziet er heel verschillend uit. Ook ben je wat beperkt in je typekeuze voor een property. Alleen primitieve types, String, Class, annotaties en enums mogen of een 1-dimensionale array hiervan. Geen objecten dus. In de praktijk is dit echter niet echt een belemmering.
Het keyword default geeft, geheel verwacht, een standaard waarde aan de property. Als je dit keyword weglaat, is deze property verplicht om in te vullen.
De overige configuratie kun je op de interface annoteren en zal ik even de vier nuttigste opties doornemen:

@Retention:
Dit geeft aan wanneer een annotatie beschikbaar is op de class. Dit kan zijn alleen tijdens build-time, tijdens compile-time of tijdens runtime. Zie de enum RetentionPolicy.

@Target
Dit geeft aan waar de annotatie geldig is, bv. op types, fields of methods. Zie de enum ElementType.

@Documented
Dit geeft aan of de annotatie ook wordt meegenomen met de Javadoc.

@Inherited
Dit geeft aan of de annotatie ook wordt doorgegeven via inheritance.

Onze annotatie zie er na configuratie er als volgt uit:

@Retention(value=RetentionPolicy.RUNTIME)
@Target(value={ElementType.TYPE})
@Documented
public @interface Ranked {

}

Dus kunnen we deze annotatie tijdens runtime nog steeds gebruiken en mag deze alleen op classes worden gebruikt. De @Documented spreekt vanzelf.
Nu is de annotatie klaar voor gebruik op de bekend manier:

/*
* Deze class is geranked.
*/
@Ranked
public class Product {

}
 
Nu moeten we ook nog wat met deze property gaan doen, want ook al lijkt Spring soms magisch, het werkt niet vanzelf. Onze magie zit bijvoorbeeld in de DAO, waar we entiteiten met @Ranked automatisch sorteren. (Ja, ik weet dat dit ook kan met @Sort kan)

if (persistentClass.isAnnotationPresent(Ranked.class)) {
            return findByCriteriaOrdered(Order.desc(RANK));
}

Waar het hier om gaat is de method isAnnotationPresent van de class Class. Deze kijkt of een annotatie tijdens runtime (vandaar de RetentionPolicy) in de class aanwezig is. Als dat zo is, kun je daarmee iets doen, zoals hier gebeurd.


Tagged in: Reflection , Java SE , Java EE 6 , Java EE
evdh
evdh

Dan Dyer shares 10 tips for publishing open source Java libraries. Read more at his original post.

He recommends to:

1. Make the download link prominent.


Tagged in: Open Source , Java SE
ppow
ppow

Probably most of the Java users is aware that String object is more complex than just an array of char. To make the usage of strings in Java more robust additional measures were taken – for instance the String pool was created to save memory by reusing the same String objects instead of allocating new ones.

Another optimisation that is adding the offset and count fields to the String object instances to improve the performance of substring() method. Even though this mechanism is very helpful in practice, not many people are aware how easily you can create a major memory leak because of that! (check out this article if you're interested). It is funny how in Java even simpliest stuff can bite you in your behind:)


Tagged in: String , Memory , Leak , Java SE
svanhugten
svanhugten

 

Het uploaden van bestanden is vaak een niet-triviale taak. Eerst moet je het bestand worden gevalideerd op type en grootte, naar een tijdelijke bestemming worden gestreamed en daarna gekopieerd, wat nu al simpeler klinkt dan het is als je het zelf moet doen.
Met RichFaces wordt het echter een stuk simpeler, een oplossing die ik jullie niet wilde onthouden.

De component:

Met de <rich:fileUpload> tag plaats je de component. In mijn geval ziet het er als volgt uit:

<rich:fileUpload maxFilesQuantity="1"
            immediateUpload="true"  onsizerejected=
"alert('Uw bestand mag niet groter dan 1000KB zijn');"
            ontyperejected=
"alert('Alleen *.jpg, *.gif, *.png en *.bmp bestanden zijn toegestaan als plaatje');"
            acceptedTypes=
"jpg, gif, png, bmp"
            fileUploadListener="#{bean.upload}">
</rich:fileUpload>


Dit creëert een upload-component dat één plaatje accepteert en het meteen upload na het selecteren. Als het groter is dan 1000KB (te configureren als maxRequestSize init-param bij het rich-faces filter in web.xml) of als niet voldoet aan de bestandtype-eis, dan geeft dit component netjes een melding. De listener verwijst naar een specifiek event in de achterliggende bean.

public void upload(UploadEvent event) throws IOException {
        UploadItem item = event.getUploadItem();
        String filePath = //path waar het bestand naar toe moet

        File file = new File(filePath);
        file.createNewFile();
        FileOutputStream fos = new FileOutputStream(file);
        // In de web.xml is ook weer configureren of er  tijdelijke bestanden worden
        // gemaakt of dat alleen het geheugen wordt gebruikt. Standaard wordt er
        // gebruik gemaakt van tijdelijke bestanden.
        //<init-param>
        //   <param-name>createTempFiles</param-name>
        //   <param-value>true</param-value>
        //</init-param>   
        if (item.isTempFile()) {
            FileInputStream fis = new FileInputStream(item.getFile());
            IOUtils.write(IOUtils.toByteArray(fis), fos);
            fis.close();
        } else {
            IOUtils.write(item.getData(), fos);
        }
        fos.close();
}


Merk op dat ik bij deze code ook de IOUtils uit Apache Commons gebruik om de bestandsafhandeling aanzienlijk te vereenvoudigen.
Hiermee is het bestand geupload, inclusief nette afhandeling van eventuele fouten. Bedankt RichFaces!











































Tagged in: RichFaces , Java SE , Java EE , Ajax4JSF
evdh
evdh

As indicated by Jeanne Boyarsky, Oracle/Sun is reinventing the SCJP into the Sun Java Programmer Plus Certification.  The big difference is the new exam will require hands on programming instead of memorizing obscure details.

This exam is not yet implemented, but in beta stage and Sun is looking for interested developers to try out this new approach. If you're interested, you can sign up for this.

Personally, I think this is a good step. Currently, preparation for the exam seems to involve reading one or more exam preparation guides, memorizing APIs and getting your hands on a number of test exams. Good programmers who haven't done that will not automatically pass, but bad programmers who put in the right effort might. Of course, we'll have to wait and see how it will be implemented in the end.


Tagged in: Java SE , Certification
evdh
evdh

Would you expect the following code to produce different results when comparing with '==' ?

 

Example 1:


Tagged in: Java SE
svanhugten
svanhugten

Sinds een tijdje (ergens rond Eclipse 3.3/3.4) treedt er een lastig probleem op in de volgende situatie:

 

- Je hebt een web applicatie project in Eclipse
- Je bouwt de war met Maven
- Je deployed het binnen Eclipse met de standaard Tomcat-plugin


Tagged in: Web applications , Maven , Java SE , Java EE
svanhugten
svanhugten ‘Nee' is mijn eerste antwoord en waarom wil ik graag met jullie delen. Een typische Java bean ziet er als volgt uit:

public class BankAccount {

private long number;

private Customer owner;

private double balance;

public long getNumber() {

return this.number;

}

public void setNumber(long number) {

this.number = number;

}

Etc...


}


Niet veel mis mee zou je zeggen. Op zich is hier ook mee te werken, maar is een goede Object Oriented class? Je bent geneigd om ‘Ja' te antwoorden, maar als je de class eens goed bekijkt, begint er wat te kriebelen. Houdt deze class zit netjes aan het encapsulation-principe? De class members zijn private gedeclareerd, maar door automatisch getter/setter-paren te maken, heeft iemand die gebruik maakt van de class toch de volledige controle over de interne staat van het object. Bovendien kun je op deze manier nooit de staat van jouw object garanderen. Op ieder moment kan iemand in de code de inhoud van jouw object veranderen!

Om de staat van jouw object te garanderen, kun je een heel logische manier te gebruiken om dit af te dwingen; de constructor. Door af te stappen van het gebruik van de default constructor en dan vervolgens de class member met setters te vullen, kun je afdwingen dat een object wordt aangemaakt op de manier zoals jij het bedoelt hebt.

Een BankAccount mag bijvoorbeeld niet zonder owner worden aangemaakt, noch mag het saldo bij opening negatief zijn. Volgens de standaard manier is dit gemakkelijk wel eens te vergeten.

BankAccount newAcc = new BankAccount();

newAcc.setNumber(1023L);

newAcc.setBalance(-100.00);

...wat business logic met de account

// Oeps, customer vergeten


Zo krijg je dus een hoop ongewenste situaties. Beter is dus:

BankAccount newAcc = new BankAccount(1023L, customer, 100L);


Waarbij de constructor er als volgt uitziet:

public BankAccount(long number, Customer owner, double balance) {

if (customer == null) {

throw new IllegalStateException("Customer can't be NULL");

}


if (balance < 0) {

throw new IllegalStateException("Opening balance can't be negative");

}


this.number = number;

this.owner = owner;

this.balance = balance;

}


Zo ben je er altijd van verzekerd dat een BankAccount correct wordt geconstrueerd. Bovendien geeft dit een single point of construction, want zonder setters kan de state van dit object niet meer veranderen. Eenmaal correct gemaakt, betekend dat een object altijd valide is binnen het programma. Overigens kan de validatie logic een stuk korter met behulp van Apache Commons. Dan wordt de constructor als volgt:

public BankAccount(long number, Customer owner, double balance) {
Validate.notNull(customer, "Customer can't be NULL");

Validate.isTrue(balance > 0, "Opening balance can't be negative");

this.number = number;

this.owner = owner;

this.balance = balance;

}


Natuurlijk is het niet zo dat je nooit meer de staat van een object mag veranderen volgens deze manier, alleen als je dit doet, moet je de verandering controleren of het object in een valide staat blijft. Bijvoorbeeld, een bankrekeningsaldo kan veranderen:

public void changeBalance(double change) {


this.balance += change;


// Staat controleren

if (this.balance < 0 and !this.owner.canHaveNegativeBalance()) {

// Eigenaar mag niet rood staan, transactie terugdraaien

this.balance -= change;

}


}


Dit kan natuurlijk ook met een setter, maar naast een betere beschrijving van het gedrag van deze methode heeft dit ook het vaak vergeten voordeel van validatie op het object zelf. Vooral omdat de setter vaak wordt gegenereerd, wordt de validatie logica vaak in de business logic gedaan, wat fouten en duplicate code in de hand werkt. Een correcte class ziet er dus als volgt uit:

public class BankAccount {

private long number;

private Customer owner;

private double balance;

public BankAccount(long number, Customer owner, long balance) {


Validate.notNull(customer, "Customer can't be NULL");

Validate.isTrue(balance > 0, "Opening balance can't be negative");

this.number = number;

this.owner = owner;

this.balance = balance;

}

public long number() {

return number;

}


public Customer owner() {

return owner;

}

public BigDecimal balance() {

return balance;

}

public void changeBalance(double change) {

this.balance += change;


// Staat controleren

if (this.balance < 0 and !this.owner.canHaveNegativeBalance()) {

// Eigenaar mag niet rood staan, transactie terugdraaien

this.balance -= change;

}

}


}


Een laatste punt dat ik wil aanstippen, is het gebruik maken van de defensive copy techniek. Een goed voorbeeld is een getter die een collection teruggeeft:

public List<Customer> customers() {

return this.customers;

}


De bedoeling van deze method is de informatie in customers collection teruggeven en niet om hem te kunnen veranderen. Toch kan dit op deze manier, immers is een collection niet immutable en geef je het object zelf terug, dus dit is het gevolg:

List<Customers> stolenCustomers = branch.customers();

system.out.println(branch.customers().size()); //bv. 5

stolenCustomers.add(new Customer("Alan", "Johnston", etc...));

system.out.println(branch.customers().size()); //6!


Onbedoeld heeft een filiaal er dus een klant bij gekregen, zonder dat zelf te willen. Om dit te voorkomen moet er een defensief kopie worden aangemaakt, zodat de echte class member niet kan worden veranderd.

public List<Customer> customers() {

return new ArrayList(this.customers);

}


Hierdoor krijgt je bij het opvragen van de customers collection een kopie van de lijst in plaats van het originele object. Object georiënteerd programmeren klinkt tegenwoordig zo vanzelfsprekend, maar zoals je ziet gaat het gemakkelijk zelfs al op model niveau fout. Dat het werken vanuit een groeiende servicegeoriënteerde wereld ook niet echt netjes programmeren in de hand werkt, is weer een andere discussie...

Nuttige bronnen:

Validation belongs in a Model Object
Validate state with class invariants
Self-encapsulate fields
Constructors in general
Avoid JavaBeans style of construction 

Tagged in: Java SE , Java EE 6 , Java EE
« StartPrev12NextEnd »

Tags:

Sponsers