Here's some random snippets for a better understanding of Java.
- New in 11
- Zulu builds
- Inner classes
- Passing Reference Data Type Arguments
- Stop Returning Null
- Enum
- Annotations
- Try with resources
- Interfaces
- Generic methods
- Stream
- Private constructor
- Web applications
Inside a method body, the new keyword var
replaces the type. It's not allowed when the compiler is incapable of infering the correct type of the variable.
// doesn't compile
var text = "Yo!";
text = 23; // Incompatible types
var request = HttpRequest.newBuilder()
.uri(URI.create("https//www.google.com"))
.GET() // optional because default request method
.build();
var client = HttpClient.newHttpClient();
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) // use send() for the synchronous solution
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
var request = HttpRequest.newBuilder()
.uri(URI.create("https://postman-echo.com/post"))
.header("Content-Type", "text/plain")
.POST(HttpRequest.BodyPublishers.ofString("Hi there!"))
.build();
var client = HttpClient.newHttpClient();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
var request = HttpRequest.newBuild()
.uri(URI.create("https://postman-echo.com/basic-auth"))
.build();
var client = HttpClient.newBuilder()
.authenticator(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("postman", "password".toCharArray());
}
})
.build();
var response = client.send(request, HttpResponse::BodyHandlers.ofString());
System.out.println(response.statusCode()); // 200
On macOS & other BSD/Linux systems, use /usr/libexec/java_home -v
1.8to generate your
$PATHas JavaEE is not for Java 9 and beyond (I had some issues w/ Java 15 Tomcat programs running well but maven/Hibernate standalone JAR/WAR or log4j2 failed; worked well with Glassfish 5.x by the way, because of the hardcoded path in
asenv.conf`).
public class ShadowTest {
public int x = 0;
class FirstLevel {
public int x = 1;
void methodInFirstLevel(int x) { // instance method
System.out.println("x = " + x); // 23
System.out.println("this.x = " + this.x); // Should be 1
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x); // should be 0
}
}
public static void main(String... args){
ShadowTest st = new ShadowTest();
ShadowTest.FirstLevel fl = st.new FirstLevel(); // instance method so you must create an instance st of Shadowtest
fl.methodInFirstLevel(23);
}
}
public class DataStructure {
// Create an array
private final static int SIZE = 15;
private int[] arrayOfInts = new int[SIZE];
public DataStructure() {
// fill the array with ascending integer values
for (int i = 0; i < SIZE; i++) {
arrayOfInts[i] = i;
}
}
public void printEven() {
// Print out values of even indices of the array
DataStructureIterator iterator = this.new EvenIterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
}
interface DataStructureIterator extends java.util.Iterator<Integer> { }
// Inner class implements the DataStructureIterator interface,
// which extends the Iterator<Integer> interface
private class EvenIterator implements DataStructureIterator {
// Start stepping through the array from the beginning
private int nextIndex = 0;
public boolean hasNext() {
// Check if the current element is the last in the array
return (nextIndex <= SIZE - 1);
}
public Integer next() {
// Record a value of an even index of the array
Integer retValue = Integer.valueOf(arrayOfInts[nextIndex]);
// Get the next even element
nextIndex += 2;
return retValue;
}
}
public static void main(String s[]) {
// Fill the array with integer values and print out only
// values of even indices
DataStructure ds = new DataStructure();
ds.printEven();
}
}
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
public class TestCircle{
public static void main(String[] args){
Circle circle = new Circle(); // constructor set (0,0)
TestCircle tester = new TestCircle();
System.out.println(circle.getX() + " . " + circle.getY()); // 0,0
tester.moveCircle(circle,1,1);
System.out.println(circle.getX() + " . " + circle.getY()); // 1,1 ie side effect on the fields
}
public void moveCircle(Circle circle, int deltaX, int deltaY){
// reference data type parameters are also passed by value;
// however, the values of the object's fields can be changed
circle.setX(circle.getX() + deltaX);
circle.setY(circle.getY() + deltaY);
// assign a new reference to circle (no permanence)
circle = new Circle(0,0);
}
}
As a collection, you can use Collections.emptyList()
or since Java 9, List.of()
like in Lisp. Otherwise, Brian Goetz, Java Language Architect at Oracle, has introduced in Java 8 a monad like Maybe
in Haskell.
import java.util.Optional;
import java.util.List;
import java.util.ArrayList;
public class TestOptional {
// Task has:
// fields: name : String, status : boolean
// constructor: this(String name)
private List<Task> tasks = new ArrayList<>();
public Optional<Task> seekTask(String name){
for (Task task : tasks) {
if (task.getName() == name) {
return Optional.of(task);
}
}
return Optional.empty();
}
public static void main(String[] args){
TestOptional tester = new TestOptional();
tester.tasks.add(new Task("foo"));
tester.tasks.add(new Task("baz"));
Optional<Task> goodTask = tester.seekTask("foo");
goodTask.ifPresent(System.out::println);
goodTask.ifPresent(value -> {
System.out.println(value.getName());
});
Optional<Task> noTask = tester.seekTask("barNotBaz");
noTask.ifPresentOrElse(value -> {
System.out.println(value.getName());
}, () -> System.err.println("Not found"));
}
}
Notice the use of the lambda expressions (modern JavaScript also has the arrow functions; mandatory to make clean lexical closures)!
You also can use Optional.ofNullable(anObject)
as if the specified value is null, then this method returns an empty instance of the Optional class: Optional.empty
.
public enum Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7);
private final double mass; // in kilograms
private final double radius; // in meters
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
private double mass() { return mass; }
private double radius() { return radius; }
// universal gravitational constant (m3 kg-1 s-2)
public static final double G = 6.67300E-11;
double surfaceGravity() {
return G * mass / (radius * radius);
}
double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
public static void main(String[] args) {
if (args.length != 1) {
System.err.println("Usage: java Planet <earth_weight>");
System.exit(-1);
}
double earthWeight = Double.parseDouble(args[0]);
double mass = earthWeight/EARTH.surfaceGravity();
for (Planet p : Planet.values()) // values() in Enum
System.out.printf("Your weight on %s is %f%n",
p, p.surfaceWeight(mass));
}
}
import java.lang.annotation.*; // import this to use @Documented
@Documented // used to make the intel in @ClassPreamble appear in Javadoc-generated documentation
@interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
// Note use of array
String[] reviewers();
}
// usage
@ClassPreamble (
author = "Martial Boniou",
date = "12/12/2020",
currentRevision = 6,
lastModified = "14/12/2020",
lastModifiedBy = "Martial Boniou",
// Note array notation
reviewers = {"Alan Kay", "Cousin Eddie", "Martin Fowler"}
)
public class TestAnnotation {
public static void main(String... args){
System.out.println("And now, the bishop...");
}
}
Source: Custom Annotations by Justin Albano
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonField {
public String value() default "";
}
public class Car {
@JsonField("manufacturer") // the name of the parameter (value) can be omitted because only one
private final String make;
@JsonField
private final String model;
private final String year;
public Car(String make, String model, String year) {
this.make = make;
this.model = model;
this.year = year;
}
public String getMake() {
return make;
}
public String getModel() {
return model;
}
public String getYear() {
return year;
}
@Override
public String toString() {
return year + " " + make + " " + model;
}
}
import java.lang.Object;
import java.lang.reflect.Field;
import java.util.Objects; // or /import static java.util.Objects.requireNonNull/ for direct sugae
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors; // or /import static java.util.stream.Collectors.joining/ for direct usage
public class JsonSerializer {
public String serialize(Object object) throws JsonSerializeException {
try {
Class<?> objectClass = Objects.requireNonNull(object).getClass();
Map<String, String> jsonElements = new HashMap<>();
for (Field field: objectClass.getDeclaredFields()) {
// Next, tell the reflection API to suppress the standard Java
// access checking in order to access the private field
field.setAccessible(true);
if (field.isAnnotationPresent(JsonField.class)) {
jsonElements.put(getSerializedKey(field), (String) field.get(object));
}
}
System.out.println(toJsonString(jsonElements));
return toJsonString(jsonElements);
}
catch (IllegalAccessException e) {
throw new JsonSerializeException(e.getMessage());
}
}
private String toJsonString(Map<String, String> jsonMap) {
String elementString = jsonMap.entrySet()
.stream()
.map(entry -> "\"" + entry.getKey() + "\":\"" + entry.getValue() + "\"")
.collect(Collectors.joining(",")); // works like fold, reduce, #inject:into: in function languages, ruby, Smalltalk resp.
return "{" + elementString + "}";
}
private static String getSerializedKey(Field field) {
String annotationValue = field.getAnnotation(JsonField.class).value();
return (annotationValue.isEmpty()) ? field.getName() : annotationValue;
}
}
Check the elegant JsonSerializableFieldExtractor refactoring here.
public class JsonSerializeException extends Exception {
// use serialver to generate this one
private static final long serialVersionUID = 8713387492080807461L;
public JsonSerializeException(String message) {
super(message);
}
}
public class TestJsonSerializer {
public static void main (String... args) {
Car car = new Car("Citroen", "Xsara", "2004");
JsonSerializer serializer = new JsonSerializer();
try {
serializer.serialize(car);
}
catch (JsonSerializeException e) {
System.out.println(e.getMessage());
}
}
}
Java try with resources construct is an exception handling mechanism that automatically close resources like InputStream
or a JDBC connection. Here's an example:
private static void printFile() throws IOException {
try(FileInputStream input = new FileInputStream("file.txt")) {
int data = input.read();
while (data != -1) {
System.out.println((char) data);
data = input.read();
}
}
}
Since Java 9, you can create a resource outside the parentheses:
FileInputStream input = new FileInputStream("file.txt");
try (input) { // new syntax
{...}
Make your own with:
public interface AutoClosable {
public void close() throws Exception;
}
The methods in an interface are public and abstract, so it's not useful to write them with the public
and/or abstract
keywords. It's not recommended to write these keywords according to the Java SE specifications by Oracle.
/* when you got */
public interface Relatable {
int isGreaterThan(Relatable object);
}
/* you can write a class */
import java.lang.Integer;
public class MyClass implements Relatable {
public int value;
public boolean isGreaterThan(Relatable other) {
MyClass otherClass = (MyClass)other;
return Integer.signum(this.value - otherClass.value);
}
}
REMINDER: When you extend an interface that contains a default method, you can do the following:
- not mention the default method at all, which lets your extended interface inherit the default method;
- redeclare the default method, which makes it abstract;
- redefine the default method, which overrides it.
BEWARE: if 2 or more independently defined default methods conflict, or a default method conflicts with an abstract method, then the Java compiler produces a compiler error. You must explicitly override the supertype methods, like in this example:
// incomplete code
public interface OperateCar {
default int startEngine(EncryptedKey key) {
// Implementation
{...}
}
}
public interface FlyCar {
default int startEngine(EncryptedKey key) {
// Implementation
{...}
}
}
The following class must override the method startEngine
:
public class FlyingCar implements OperateCar, FlyCar {
// {...}
public int startEngine(EncryptedKey key) {
FlyCar.super.startEngine(key);
OperateCar.super.startEngine(key);
}
}
You could invoke any of the default implementations (from OperateCar
and FlyCar
) with the super
keyword.
IMPORTANT: All fields in interfaces are automatically public, static and final, and all methods that you declare or define (as default methods) are public. With abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods.
The syntax for a generic method includes a list of type parameters, inside angle brackets, which appears before the method's return type.
public class Util {
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
return p1.getValue().equals(p2.getValue());
}
}
public class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) { this.key = key; }
public void setValue(V value) { this.value = value; }
public K getKey() { return key; }
public V getValue() { return value; }
}
The complete syntax for invoking this static method would be:
Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "orange");
// syntax one
boolean isSame = Util.<Integer, String>compare(p1, p2);
// syntax two
boolean isSame = Util.compare(p1, p2); // inference checked by the compiler
You should use the syntax two.
Since Java 8, it's a monad. Here's some examples:
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.IntStream;
import java.util.List;
import java.util.Arrays;
public class TestStream {
public static void main(String... args) {
List<String> myList = Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList
.stream()
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println); //C1\nC2
Stream.of("a1", "a2", "a3") // directly
.findFirst()
.ifPresent(System.out::println); //a1
IntStream.range(1, 4) // useful w/ forEach to replace the regular for-loop
.mapToObj(i -> "a" + i)
.forEach(System.out::println); //a1\na2\na3
Stream.of("a1", "a2", "a3")
.map(s -> s.substring(1))
.mapToInt(Integer::parseInt) // also mapToLong(), mapToDouble()
.max()
.ifPresent(System.out::println); //3
/* experiment laziness */
System.out.println("Lazy1");
Stream.of("d2", "a2", "b1", "b3", "c")
.filter(s -> {
System.out.println("filter: " + s); //nothing b/c intermediate operations will only be executed when a terminal operation is present
return true;
});
System.out.println("Lazy2");
Stream.of("d2", "a1")
.filter(s -> {
System.out.println("filter: " + s);
return true;
})
.forEach(s -> System.out.println("forEach: " + s));
/*
* filter: d2
* forEach: d2
* filter: a1
* forEach: a1
*/
}
}
Notice the laziness of the operations.
Streams cannot be reused but:
import java.util.*;
import java.util.stream.Stream;
import java.util.function.Supplier;
public class TestSupplierStream {
public static void main(String... args) {
Supplier<Stream<String>> streamSupplier =
() -> Stream.of("d2", "a2", "b1")
.filter(s -> s.startsWith("a"));
System.out.println(streamSupplier.get().anyMatch(s -> true)); // true
System.out.println(streamSupplier.get().noneMatch(s -> true)); // false (no IllegalStateException)
}
}
Check this for more intel about the Supplier<T>
interface.
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.List;
import java.util.Arrays;
public class TestAdvancedStream {
public static void main(String... args) {
// package-private fields
class Person {
String name;
int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name;
}
}
List<Person> persons = Arrays.asList(
new Person("Max", 18),
new Person("Peter", 23),
new Person("Pamela", 23),
new Person("David", 12)
);
// Simple collect
List<Person> filtered =
persons
.stream()
.filter(p -> p.name.startsWith("P"))
.collect(Collectors.toList()); // as an ArrayList
System.out.println(filtered); // [Peter, Pamela]
// Group collect
Map<Integer, List<Person>> personsByAge =
persons
.stream()
.collect(Collectors.groupingBy(p -> p.age));
personsByAge
.forEach((age, p) -> System.out.format("age %s: %s\n", age, p));
/*
* age 18: [Max]
* age 23: [Peter, Pamela]
* age 12: [David]
*/
// Aggregation collect
Double averageAge = persons
.stream()
.collect(Collectors.averagingInt(p -> p.age)); // or summarizingInt() for full stats
System.out.println(averageAge); // 19.0
// Joining collect
String phrase = persons
.stream()
.filter(p -> p.age >= 18)
.map(p -> p.name)
.collect(Collectors.joining(" and ", "In Germany ", " are of legal age.")); // joining accepts a separator and optional prefix & suffix
System.out.println(phrase);
/* In Germany Max and Peter and Pamela are of legal age.
*/
// Personalizing a collector
Collector<Person, StringJoiner, String> personNameCollector =
Collector.of( // IMPORTANT: returns a new Collector described by the given supplier, accumulator, and combiner functions (static <T,R> Collector <T,R,R>)
() -> new StringJoiner(" | "), // supplier
(j,p) -> j.add(p.name.toUpperCase()), // accumulator
(j1, j2) -> j1.merge(j2), // combiner (merge 2 StringJoiners into one)
StringJoiner::toString); // finisher
String names = persons
.stream()
.collect(personNameCollector);
System.out.println(names); // MAX | PETER | PAMELA | DAVID
}
}
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.IntStream;
import java.util.List;
import java.util.ArrayList;
public class TestFlatMap {
public static void main(String... args) {
// package-private fields
class Bar {
String name;
Bar(String name) {
this.name = name;
}
}
class Foo {
String name;
List<Bar> bars = new ArrayList<>();
Foo(String name) {
this.name = name;
}
}
List<Foo> foos = new ArrayList<>();
// two elegant Smalltalk-like loop to create:
// - 3 foos
// - 3 bars in each foo
IntStream
.range(1, 4)
.forEach(i -> foos.add(new Foo("Foo" + i)));
foos.forEach(f ->
IntStream
.range(1, 4)
.forEach(i -> f.bars.add(new Bar("Bar" + i + " <- " + f.name))));
//FlatMap accepts a function which has to return a stream of objects
foos.stream()
.flatMap(f -> f.bars.stream())
.forEach(b -> System.out.println(b.name));
/* Bar1 <- Foo1
* Bar2 <- Foo1
* Bar3 <- Foo1
* Bar1 <- Foo2 etc... */
// A better version:
IntStream.range(1, 4)
.mapToObj(i -> new Foo("Foo" + i))
.peek(f -> IntStream.range(1, 4) // IMPORTANT: peek NEEDS a terminal operation
.mapToObj(i -> new Bar("Bar" + i + " <- " + f.name))
.forEach(f.bars::add))
.flatMap(f -> f.bars.stream())
.forEach(b -> System.out.println(b.name));
}
}
In this example, the stream of 3 foo objects has been transformed into a stream of 9 bar objects.
If you're unsure about the usage of peek()
, check here. (REMINDER: all intermediate operations like peek()
are lazy, and, as a result, no operations will have any effect until the pipeline starts to work.)
Try this code example with the persons
instance assigned in the collect section.
persons
.stream()
.reduce((p1,p2) -> p1.age > p2.age ? p1 : p2) // a BinaryOperator accumulator
.ifPresent(System.out::println); // Pamela
Person result =
persons
.stream()
.reduce(new Person("", 0), (p1, p2) -> { // both an identity value AND a BinaryOperator accumulator
p1.age += p2.age;
p1.name += p2.name;
return p1;
});
System.out.format("name=%s; age=%s\n", result.name, result.age); // name=MaxPeterPamelaDavid; age=76
Integer ageSum = persons
.stream() // replace with .parallelStream() to test the parallel version
.reduce(
0, // an identity value
(sum, p) -> sum += p.age, // a BiFunction accumulator
(sum1, sum2) -> sum1 + sum2); // a BinaryOperator combiner
System.out.println(ageSum); // 76
If you use stream()
, only the accumulator is invoked. If you switched to the parallel stream version parallelStream()
, the combiner is invoked too (and both works together). Check the next section.
Add -Djava.util.concurrent.ForkJoinPool.common.parallelism=<number>
to the JVM parameter in the command line if you want to maximize the number of threads, otherwise you'll use the default (7 on my Macbook Air M1).
import java.util.concurrent.ForkJoinPool;
import java.util.Arrays;
public class TestParallelStreams {
public static void main(String... args) {
// Checking
ForkJoinPool commonPool = ForkJoinPool.commonPool();
System.out.println(commonPool.getParallelism());
// ParallelStream
Arrays.asList("a1", "a2", "b1", "c2", "c1")
.parallelStream()
.filter(s -> {
System.out.format("filter: %s [%s]\n",
s, Thread.currentThread().getName());
return true;
})
.map(s -> {
System.out.format("map: %s [%s]\n",
s, Thread.currentThread().getName());
return s.toUpperCase();
})
.sorted((s1, s2) -> { // sort is executed sequentially on the main thread onl
System.out.format("sort: %s <> %s [%s]\n",
s1, s2, Thread.currentThread().getName());
return s1.compareTo(s2);
})
.forEach(s -> System.out.format("forEach: %s [%s]\n",
s, Thread.currentThread().getName()));
}
}
If the length of the specified array is less than the minimum granulatity, then it is sorted using the appropriate Arrays.sort
method (instead of Arrays.parallelSort()
).
As in the Singleton pattern:
class Singleton {
private static Singleton instance;
int a;
private Singleton() { // private constructor
a = 10;
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public String toString() {
return String.valueOf(a);
}
}
When I tried JPA/EJB by hand, I checked the Dominique Liard's tutorial (in french) and I enjoyed this demo but I prefered to create a Maven project with these pom.xml
and src/main/resources/META-INF/persistence.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.hondana</groupId>
<artifactId>intro-jpa</artifactId>
<packaging>jar</packaging>
<version>0.1.0</version>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.17.Final</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.17.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<!--<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<mainClass>net.hondana.webstore.Console</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>net.hondana.webstore.Console</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources/META-INF</directory>
<targetPath>META-INF</targetPath>
<includes>
<include>persistence.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="WebStore">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>net.hondana.webstore.business.Article</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"></property>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/WebStore?useSSL=false"></property>
<property name="javax.persistence.jdbc.user" value="root"></property>
<property name="javax.persistence.jdbc.password" value="root"></property>
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
</persistence>
If you don't use a Maven Wrapper, you may have to repackage
(according to remko de knikker, by adding repackage
in the executions:execution:goals:goal node in the spring-boot-maven-plugin
node of build:plugins:plugin):
mvn -N io.takari:maven:wrapper
./mvnw clean install
./mvnw spring-boot:run
In case of problem, you can simply remove the binaries.
In order to try Glassfish 5, I've had to install 5.0 because there's a bug in 5.1 (malformed enctype
in the <form>
: application/x-www-form-urlencoded
instead of multipart/form-data
). I've been able to deploy some WARs by disabling the Implicit CDI. For a clean MySQL integration, you need a connector JAR in the domain's lib/ext
and a correct JDBC Connection Pool, say:
- Resource Type:
javax.sql.DataSource
; - Datasource Classname:
com.mysql.cj.jdbc.MysqlDataSource
; - URL:
jdbc:mysql://localhost:3306
; - useSSL:
false
.
You can use jdbc:mysql://localhost:3306?useSSL=false
directly as URL.
Published by Martial BONIOU (2021-03-19)