diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Constants.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Constants.java new file mode 100644 index 0000000000..b646c686b2 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Constants.java @@ -0,0 +1,47 @@ +package com.baeldung.algorithms.multiswarm; + +/** + * Constants used by the Multi-swarm optimization algorithms. + * + * @author Donato Rimenti + * + */ +public class Constants { + + /** + * The inertia factor encourages a particle to continue moving in its + * current direction. + */ + public static final double INERTIA_FACTOR = 0.729; + + /** + * The cognitive weight encourages a particle to move toward its historical + * best-known position. + */ + public static final double COGNITIVE_WEIGHT = 1.49445; + + /** + * The social weight encourages a particle to move toward the best-known + * position found by any of the particle’s swarm-mates. + */ + public static final double SOCIAL_WEIGHT = 1.49445; + + /** + * The global weight encourages a particle to move toward the best-known + * position found by any particle in any swarm. + */ + public static final double GLOBAL_WEIGHT = 0.3645; + + /** + * Upper bound for the random generation. We use it to reduce the + * computation time since we can rawly estimate it. + */ + public static final int PARTICLE_UPPER_BOUND = 10000000; + + /** + * Private constructor for utility class. + */ + private Constants() { + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/FitnessFunction.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/FitnessFunction.java new file mode 100644 index 0000000000..2d86ec8d94 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/FitnessFunction.java @@ -0,0 +1,21 @@ +package com.baeldung.algorithms.multiswarm; + +/** + * Interface for a fitness function, used to decouple the main algorithm logic + * from the specific problem solution. + * + * @author Donato Rimenti + * + */ +public interface FitnessFunction { + + /** + * Returns the fitness of a particle given its position. + * + * @param particlePosition + * the position of the particle + * @return the fitness of the particle + */ + public double getFitness(long[] particlePosition); + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Multiswarm.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Multiswarm.java new file mode 100644 index 0000000000..ef60726278 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Multiswarm.java @@ -0,0 +1,227 @@ +package com.baeldung.algorithms.multiswarm; + +import java.util.Arrays; +import java.util.Random; + +/** + * Represents a collection of {@link Swarm}. + * + * @author Donato Rimenti + * + */ +public class Multiswarm { + + /** + * The swarms managed by this multiswarm. + */ + private Swarm[] swarms; + + /** + * The best position found within all the {@link #swarms}. + */ + private long[] bestPosition; + + /** + * The best fitness score found within all the {@link #swarms}. + */ + private double bestFitness = Double.NEGATIVE_INFINITY; + + /** + * A random generator. + */ + private Random random = new Random(); + + /** + * The fitness function used to determine how good is a particle. + */ + private FitnessFunction fitnessFunction; + + /** + * Instantiates a new Multiswarm. + * + * @param numSwarms + * the number of {@link #swarms} + * @param particlesPerSwarm + * the number of particle for each {@link #swarms} + * @param fitnessFunction + * the {@link #fitnessFunction} + */ + public Multiswarm(int numSwarms, int particlesPerSwarm, FitnessFunction fitnessFunction) { + this.fitnessFunction = fitnessFunction; + this.swarms = new Swarm[numSwarms]; + for (int i = 0; i < numSwarms; i++) { + swarms[i] = new Swarm(particlesPerSwarm); + } + } + + /** + * Main loop of the algorithm. Iterates all particles of all + * {@link #swarms}. For each particle, computes the new fitness and checks + * if a new best position has been found among itself, the swarm and all the + * swarms and finally updates the particle position and speed. + */ + public void mainLoop() { + for (Swarm swarm : swarms) { + for (Particle particle : swarm.getParticles()) { + + long[] particleOldPosition = particle.getPosition().clone(); + + // Calculate the particle fitness. + particle.setFitness(fitnessFunction.getFitness(particleOldPosition)); + + // Check if a new best position has been found for the particle + // itself, within the swarm and the multiswarm. + if (particle.getFitness() > particle.getBestFitness()) { + particle.setBestFitness(particle.getFitness()); + particle.setBestPosition(particleOldPosition); + + if (particle.getFitness() > swarm.getBestFitness()) { + swarm.setBestFitness(particle.getFitness()); + swarm.setBestPosition(particleOldPosition); + + if (swarm.getBestFitness() > bestFitness) { + bestFitness = swarm.getBestFitness(); + bestPosition = swarm.getBestPosition().clone(); + } + + } + } + + // Updates the particle position by adding the speed to the + // actual position. + long[] position = particle.getPosition(); + long[] speed = particle.getSpeed(); + + position[0] += speed[0]; + position[1] += speed[1]; + + // Updates the particle speed. + speed[0] = getNewParticleSpeedForIndex(particle, swarm, 0); + speed[1] = getNewParticleSpeedForIndex(particle, swarm, 1); + } + } + } + + /** + * Computes a new speed for a given particle of a given swarm on a given + * axis. The new speed is computed using the formula: + * + *
+	 * ({@link Constants#INERTIA_FACTOR} * {@link Particle#getSpeed()}) + 
+	 * (({@link Constants#COGNITIVE_WEIGHT} * random(0,1)) * ({@link Particle#getBestPosition()} - {@link Particle#getPosition()})) +
+	 * (({@link Constants#SOCIAL_WEIGHT} * random(0,1)) * ({@link Swarm#getBestPosition()} - {@link Particle#getPosition()})) + 
+	 * (({@link Constants#GLOBAL_WEIGHT} * random(0,1)) * ({@link #bestPosition} - {@link Particle#getPosition()}))
+	 * 
+ * + * @param particle + * the particle whose new speed needs to be computed + * @param swarm + * the swarm which contains the particle + * @param index + * the index of the particle axis whose speeds needs to be + * computed + * @return the new speed of the particle passed on the given axis + */ + private int getNewParticleSpeedForIndex(Particle particle, Swarm swarm, int index) { + return (int) ((Constants.INERTIA_FACTOR * particle.getSpeed()[index]) + + (randomizePercentage(Constants.COGNITIVE_WEIGHT) + * (particle.getBestPosition()[index] - particle.getPosition()[index])) + + (randomizePercentage(Constants.SOCIAL_WEIGHT) + * (swarm.getBestPosition()[index] - particle.getPosition()[index])) + + (randomizePercentage(Constants.GLOBAL_WEIGHT) + * (bestPosition[index] - particle.getPosition()[index]))); + } + + /** + * Returns a random number between 0 and the value passed as argument. + * + * @param value + * the value to randomize + * @return a random value between 0 and the one passed as argument + */ + private double randomizePercentage(double value) { + return random.nextDouble() * value; + } + + /** + * Gets the {@link #bestPosition}. + * + * @return the {@link #bestPosition} + */ + public long[] getBestPosition() { + return bestPosition; + } + + /** + * Gets the {@link #bestFitness}. + * + * @return the {@link #bestFitness} + */ + public double getBestFitness() { + return bestFitness; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(bestFitness); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + Arrays.hashCode(bestPosition); + result = prime * result + ((fitnessFunction == null) ? 0 : fitnessFunction.hashCode()); + result = prime * result + ((random == null) ? 0 : random.hashCode()); + result = prime * result + Arrays.hashCode(swarms); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Multiswarm other = (Multiswarm) obj; + if (Double.doubleToLongBits(bestFitness) != Double.doubleToLongBits(other.bestFitness)) + return false; + if (!Arrays.equals(bestPosition, other.bestPosition)) + return false; + if (fitnessFunction == null) { + if (other.fitnessFunction != null) + return false; + } else if (!fitnessFunction.equals(other.fitnessFunction)) + return false; + if (random == null) { + if (other.random != null) + return false; + } else if (!random.equals(other.random)) + return false; + if (!Arrays.equals(swarms, other.swarms)) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Multiswarm [swarms=" + Arrays.toString(swarms) + ", bestPosition=" + Arrays.toString(bestPosition) + + ", bestFitness=" + bestFitness + ", random=" + random + ", fitnessFunction=" + fitnessFunction + "]"; + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Particle.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Particle.java new file mode 100644 index 0000000000..5930a94267 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Particle.java @@ -0,0 +1,204 @@ +package com.baeldung.algorithms.multiswarm; + +import java.util.Arrays; + +/** + * Represents a particle, the basic component of a {@link Swarm}. + * + * @author Donato Rimenti + * + */ +public class Particle { + + /** + * The current position of this particle. + */ + private long[] position; + + /** + * The speed of this particle. + */ + private long[] speed; + + /** + * The fitness of this particle for the current position. + */ + private double fitness; + + /** + * The best position found by this particle. + */ + private long[] bestPosition; + + /** + * The best fitness found by this particle. + */ + private double bestFitness = Double.NEGATIVE_INFINITY; + + /** + * Instantiates a new Particle. + * + * @param initialPosition + * the initial {@link #position} + * @param initialSpeed + * the initial {@link #speed} + */ + public Particle(long[] initialPosition, long[] initialSpeed) { + this.position = initialPosition; + this.speed = initialSpeed; + } + + /** + * Gets the {@link #position}. + * + * @return the {@link #position} + */ + public long[] getPosition() { + return position; + } + + /** + * Gets the {@link #speed}. + * + * @return the {@link #speed} + */ + public long[] getSpeed() { + return speed; + } + + /** + * Gets the {@link #fitness}. + * + * @return the {@link #fitness} + */ + public double getFitness() { + return fitness; + } + + /** + * Gets the {@link #bestPosition}. + * + * @return the {@link #bestPosition} + */ + public long[] getBestPosition() { + return bestPosition; + } + + /** + * Gets the {@link #bestFitness}. + * + * @return the {@link #bestFitness} + */ + public double getBestFitness() { + return bestFitness; + } + + /** + * Sets the {@link #position}. + * + * @param position + * the new {@link #position} + */ + public void setPosition(long[] position) { + this.position = position; + } + + /** + * Sets the {@link #speed}. + * + * @param speed + * the new {@link #speed} + */ + public void setSpeed(long[] speed) { + this.speed = speed; + } + + /** + * Sets the {@link #fitness}. + * + * @param fitness + * the new {@link #fitness} + */ + public void setFitness(double fitness) { + this.fitness = fitness; + } + + /** + * Sets the {@link #bestPosition}. + * + * @param bestPosition + * the new {@link #bestPosition} + */ + public void setBestPosition(long[] bestPosition) { + this.bestPosition = bestPosition; + } + + /** + * Sets the {@link #bestFitness}. + * + * @param bestFitness + * the new {@link #bestFitness} + */ + public void setBestFitness(double bestFitness) { + this.bestFitness = bestFitness; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(bestFitness); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + Arrays.hashCode(bestPosition); + temp = Double.doubleToLongBits(fitness); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + Arrays.hashCode(position); + result = prime * result + Arrays.hashCode(speed); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Particle other = (Particle) obj; + if (Double.doubleToLongBits(bestFitness) != Double.doubleToLongBits(other.bestFitness)) + return false; + if (!Arrays.equals(bestPosition, other.bestPosition)) + return false; + if (Double.doubleToLongBits(fitness) != Double.doubleToLongBits(other.fitness)) + return false; + if (!Arrays.equals(position, other.position)) + return false; + if (!Arrays.equals(speed, other.speed)) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Particle [position=" + Arrays.toString(position) + ", speed=" + Arrays.toString(speed) + ", fitness=" + + fitness + ", bestPosition=" + Arrays.toString(bestPosition) + ", bestFitness=" + bestFitness + "]"; + } + +} diff --git a/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Swarm.java b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Swarm.java new file mode 100644 index 0000000000..e6d37bb7e6 --- /dev/null +++ b/algorithms/src/main/java/com/baeldung/algorithms/multiswarm/Swarm.java @@ -0,0 +1,155 @@ +package com.baeldung.algorithms.multiswarm; + +import java.util.Arrays; +import java.util.Random; + +/** + * Represents a collection of {@link Particle}. + * + * @author Donato Rimenti + * + */ +public class Swarm { + + /** + * The particles of this swarm. + */ + private Particle[] particles; + + /** + * The best position found within the particles of this swarm. + */ + private long[] bestPosition; + + /** + * The best fitness score found within the particles of this swarm. + */ + private double bestFitness = Double.NEGATIVE_INFINITY; + + /** + * A random generator. + */ + private Random random = new Random(); + + /** + * Instantiates a new Swarm. + * + * @param numParticles + * the number of particles of the swarm + */ + public Swarm(int numParticles) { + particles = new Particle[numParticles]; + for (int i = 0; i < numParticles; i++) { + long[] initialParticlePosition = { random.nextInt(Constants.PARTICLE_UPPER_BOUND), + random.nextInt(Constants.PARTICLE_UPPER_BOUND) }; + long[] initialParticleSpeed = { random.nextInt(Constants.PARTICLE_UPPER_BOUND), + random.nextInt(Constants.PARTICLE_UPPER_BOUND) }; + particles[i] = new Particle(initialParticlePosition, initialParticleSpeed); + } + } + + /** + * Gets the {@link #particles}. + * + * @return the {@link #particles} + */ + public Particle[] getParticles() { + return particles; + } + + /** + * Gets the {@link #bestPosition}. + * + * @return the {@link #bestPosition} + */ + public long[] getBestPosition() { + return bestPosition; + } + + /** + * Gets the {@link #bestFitness}. + * + * @return the {@link #bestFitness} + */ + public double getBestFitness() { + return bestFitness; + } + + /** + * Sets the {@link #bestPosition}. + * + * @param bestPosition + * the new {@link #bestPosition} + */ + public void setBestPosition(long[] bestPosition) { + this.bestPosition = bestPosition; + } + + /** + * Sets the {@link #bestFitness}. + * + * @param bestFitness + * the new {@link #bestFitness} + */ + public void setBestFitness(double bestFitness) { + this.bestFitness = bestFitness; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(bestFitness); + result = prime * result + (int) (temp ^ (temp >>> 32)); + result = prime * result + Arrays.hashCode(bestPosition); + result = prime * result + Arrays.hashCode(particles); + result = prime * result + ((random == null) ? 0 : random.hashCode()); + return result; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Swarm other = (Swarm) obj; + if (Double.doubleToLongBits(bestFitness) != Double.doubleToLongBits(other.bestFitness)) + return false; + if (!Arrays.equals(bestPosition, other.bestPosition)) + return false; + if (!Arrays.equals(particles, other.particles)) + return false; + if (random == null) { + if (other.random != null) + return false; + } else if (!random.equals(other.random)) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return "Swarm [particles=" + Arrays.toString(particles) + ", bestPosition=" + Arrays.toString(bestPosition) + + ", bestFitness=" + bestFitness + ", random=" + random + "]"; + } + +} diff --git a/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/LolFitnessFunction.java b/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/LolFitnessFunction.java new file mode 100644 index 0000000000..726d4c135d --- /dev/null +++ b/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/LolFitnessFunction.java @@ -0,0 +1,52 @@ +package com.baeldung.algorithms.multiswarm; + +/** + * Specific fitness function implementation to solve the League of Legends + * problem. This is the problem statement:
+ *
+ * In League of Legends, a player's Effective Health when defending against + * physical damage is given by E=H(100+A)/100, where H is health and A is armor. + * Health costs 2.5 gold per unit, and Armor costs 18 gold per unit. You have + * 3600 gold, and you need to optimize the effectiveness E of your health and + * armor to survive as long as possible against the enemy team's attacks. How + * much of each should you buy?
+ *
+ * + * @author Donato Rimenti + * + */ +public class LolFitnessFunction implements FitnessFunction { + + /* + * (non-Javadoc) + * + * @see + * com.baeldung.algorithms.multiswarm.FitnessFunction#getFitness(long[]) + */ + @Override + public double getFitness(long[] particlePosition) { + + long health = particlePosition[0]; + long armor = particlePosition[1]; + + // No negatives values accepted. + if (health < 0 && armor < 0) { + return -(health * armor); + } else if (health < 0) { + return health; + } else if (armor < 0) { + return armor; + } + + // Checks if the solution is actually feasible provided our gold. + double cost = (health * 2.5) + (armor * 18); + if (cost > 3600) { + return 3600 - cost; + } else { + // Check how good is the solution. + long fitness = (health * (100 + armor)) / 100; + return fitness; + } + } + +} diff --git a/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/MultiswarmUnitTest.java b/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/MultiswarmUnitTest.java new file mode 100644 index 0000000000..3455cd3932 --- /dev/null +++ b/algorithms/src/test/java/com/baeldung/algorithms/multiswarm/MultiswarmUnitTest.java @@ -0,0 +1,54 @@ +package com.baeldung.algorithms.multiswarm; + +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; + +import com.baeldung.algorithms.support.MayFailRule; + +/** + * Test for {@link Multiswarm}. + * + * @author Donato Rimenti + * + */ +public class MultiswarmUnitTest { + + /** + * Rule for handling expected failures. We use this since this test may + * actually fail due to bad luck in the random generation. + */ + @Rule + public MayFailRule mayFailRule = new MayFailRule(); + + /** + * Tests the multiswarm algorithm with a generic problem. The problem is the + * following:
+ *
+ * In League of Legends, a player's Effective Health when defending against + * physical damage is given by E=H(100+A)/100, where H is health and A is + * armor. Health costs 2.5 gold per unit, and Armor costs 18 gold per unit. + * You have 3600 gold, and you need to optimize the effectiveness E of your + * health and armor to survive as long as possible against the enemy team's + * attacks. How much of each should you buy?
+ *
+ * The solution is H = 1080, A = 50 for a total fitness of 1620. Tested with + * 50 swarms each with 1000 particles. + */ + @Test + public void givenMultiswarm_whenThousandIteration_thenSolutionFound() { + Multiswarm multiswarm = new Multiswarm(50, 1000, new LolFitnessFunction()); + + // Iterates 1000 times through the main loop and prints the result. + for (int i = 0; i < 1000; i++) { + multiswarm.mainLoop(); + } + + System.out.println("Best fitness found: " + multiswarm.getBestFitness() + "[" + multiswarm.getBestPosition()[0] + + "," + multiswarm.getBestPosition()[1] + "]"); + Assert.assertEquals(1080, multiswarm.getBestPosition()[0]); + Assert.assertEquals(50, multiswarm.getBestPosition()[1]); + Assert.assertEquals(1620, (int) multiswarm.getBestFitness()); + } + +} diff --git a/algorithms/src/test/java/com/baeldung/algorithms/support/MayFailRule.java b/algorithms/src/test/java/com/baeldung/algorithms/support/MayFailRule.java new file mode 100644 index 0000000000..91df78ce4a --- /dev/null +++ b/algorithms/src/test/java/com/baeldung/algorithms/support/MayFailRule.java @@ -0,0 +1,38 @@ +package com.baeldung.algorithms.support; + +import org.junit.Rule; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * JUnit custom rule for managing tests that may fail due to heuristics or + * randomness. In order to use this, just instantiate this object as a public + * field inside the test class and annotate it with {@link Rule}. + * + * @author Donato Rimenti + * + */ +public class MayFailRule implements TestRule { + + /* + * (non-Javadoc) + * + * @see org.junit.rules.TestRule#apply(org.junit.runners.model.Statement, + * org.junit.runner.Description) + */ + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try { + base.evaluate(); + } catch (Throwable e) { + // Ignore the exception since we expect this. + } + } + }; + } + +} diff --git a/apache-zookeeper/pom.xml b/apache-zookeeper/pom.xml new file mode 100644 index 0000000000..6d49d74ade --- /dev/null +++ b/apache-zookeeper/pom.xml @@ -0,0 +1,30 @@ + + 4.0.0 + com.baeldung + apache-zookeeper + 0.0.1-SNAPSHOT + jar + + + + org.apache.zookeeper + zookeeper + 3.3.2 + + + com.sun.jmx + jmxri + + + com.sun.jdmk + jmxtools + + + javax.jms + jms + + + + + diff --git a/apache-zookeeper/src/main/java/com/baeldung/zookeeper/connection/ZKConnection.java b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/connection/ZKConnection.java new file mode 100644 index 0000000000..0678250d57 --- /dev/null +++ b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/connection/ZKConnection.java @@ -0,0 +1,33 @@ +package com.baeldung.zookeeper.connection; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; + +import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.Watcher.Event.KeeperState; +import org.apache.zookeeper.ZooKeeper; + +public class ZKConnection { + private ZooKeeper zoo; + final CountDownLatch connectionLatch = new CountDownLatch(1); + + public ZKConnection() { + } + + public ZooKeeper connect(String host) throws IOException, InterruptedException { + zoo = new ZooKeeper(host, 2000, new Watcher() { + public void process(WatchedEvent we) { + if (we.getState() == KeeperState.SyncConnected) { + connectionLatch.countDown(); + } + } + }); + connectionLatch.await(); + return zoo; + } + + public void close() throws InterruptedException { + zoo.close(); + } +} diff --git a/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManager.java b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManager.java new file mode 100644 index 0000000000..0c0ad52123 --- /dev/null +++ b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManager.java @@ -0,0 +1,35 @@ +package com.baeldung.zookeeper.manager; + +import org.apache.zookeeper.KeeperException; + +public interface ZKManager { + /** + * Create a Znode and save some data + * + * @param path + * @param data + * @throws KeeperException + * @throws InterruptedException + */ + public void create(String path, byte[] data) throws KeeperException, InterruptedException; + + /** + * Get ZNode Data + * + * @param path + * @param boolean watchFlag + * @throws KeeperException + * @throws InterruptedException + */ + public Object getZNodeData(String path, boolean watchFlag); + + /** + * Update the ZNode Data + * + * @param path + * @param data + * @throws KeeperException + * @throws InterruptedException + */ + public void update(String path, byte[] data) throws KeeperException, InterruptedException, KeeperException; +} diff --git a/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManagerImpl.java b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManagerImpl.java new file mode 100644 index 0000000000..adf76bc0f2 --- /dev/null +++ b/apache-zookeeper/src/main/java/com/baeldung/zookeeper/manager/ZKManagerImpl.java @@ -0,0 +1,58 @@ +package com.baeldung.zookeeper.manager; + +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; +import org.apache.zookeeper.ZooDefs; +import org.apache.zookeeper.ZooKeeper; + +import com.baeldung.zookeeper.connection.ZKConnection; + +public class ZKManagerImpl implements ZKManager { + private static ZooKeeper zkeeper; + private static ZKConnection zkConnection; + + public ZKManagerImpl() { + initialize(); + } + + /** * Initialize connection */ + private void initialize() { + try { + zkConnection = new ZKConnection(); + zkeeper = zkConnection.connect("localhost"); + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + + public void closeConnection() { + try { + zkConnection.close(); + } catch (InterruptedException e) { + System.out.println(e.getMessage()); + } + } + + public void create(String path, byte[] data) throws KeeperException, InterruptedException { + zkeeper.create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); + } + + public Object getZNodeData(String path, boolean watchFlag) { + try { + byte[] b = null; + b = zkeeper.getData(path, null, null); + String data = new String(b, "UTF-8"); + System.out.println(data); + return data; + } catch (Exception e) { + System.out.println(e.getMessage()); + } + return null; + } + + public void update(String path, byte[] data) throws KeeperException, InterruptedException { + int version = zkeeper.exists(path, true) + .getVersion(); + zkeeper.setData(path, data, version); + } +} diff --git a/checker-plugin/pom.xml b/checker-plugin/pom.xml new file mode 100644 index 0000000000..bc7a669d4f --- /dev/null +++ b/checker-plugin/pom.xml @@ -0,0 +1,114 @@ + + 4.0.0 + com.baeldung + checker-plugin + jar + 1.0-SNAPSHOT + checker-plugin + http://maven.apache.org + + + + + + ${org.checkerframework:jdk8:jar} + + + + + + + + + + org.checkerframework + checker-qual + 2.3.1 + + + org.checkerframework + checker + 2.3.1 + + + org.checkerframework + jdk8 + 2.3.1 + + + + org.checkerframework + compiler + 2.3.1 + + + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + + properties + + + + + + + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + + + 10000 + 10000 + + + + org.checkerframework.checker.nullness.NullnessChecker + org.checkerframework.checker.interning.InterningChecker + org.checkerframework.checker.fenum.FenumChecker + org.checkerframework.checker.formatter.FormatterChecker + org.checkerframework.checker.regex.RegexChecker + + + -AprintErrorStack + + + -Xbootclasspath/p:${annotatedJdk} + + + + + + -Awarns + + + + + + + diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/FakeNumExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/FakeNumExample.java new file mode 100644 index 0000000000..f1769cfdea --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/FakeNumExample.java @@ -0,0 +1,42 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.fenum.qual.Fenum; + +//@SuppressWarnings("fenum:assignment.type.incompatible") +public class FakeNumExample { + + // Here we use some String constants to represents countries. + static final @Fenum("country") String ITALY = "IT"; + static final @Fenum("country") String US = "US"; + static final @Fenum("country") String UNITED_KINGDOM = "UK"; + + // Here we use other String constants to represent planets instead. + static final @Fenum("planet") String MARS = "Mars"; + static final @Fenum("planet") String EARTH = "Earth"; + static final @Fenum("planet") String VENUS = "Venus"; + + // Now we write this method and we want to be sure that + // the String parameter has a value of a country, not that is just a String. + void greetCountries(@Fenum("country") String country) { + System.out.println("Hello " + country); + } + + // Similarly we're enforcing here that the provided + // parameter is a String that represent a planet. + void greetPlanets(@Fenum("planet") String planet) { + System.out.println("Hello " + planet); + } + + public static void main(String[] args) { + + FakeNumExample obj = new FakeNumExample(); + + // This will fail because we pass a planet-String to a method that + // accept a country-String. + obj.greetCountries(MARS); + + // Here the opposite happens. + obj.greetPlanets(US); + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/FormatExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/FormatExample.java new file mode 100644 index 0000000000..2fa53ff2c2 --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/FormatExample.java @@ -0,0 +1,23 @@ +package com.baeldung.typechecker; + +public class FormatExample { + + public static void main(String[] args) { + + // Just enabling org.checkerframework.checker.formatter.FormatterChecker + // we can be sure at compile time that the format strings we pass to format() + // are correct. Normally we would have those errors raised just at runtime. + // All those formats are in fact wrong. + + String.format("%y", 7); // error: invalid format string + + String.format("%d", "a string"); // error: invalid argument type for %d + + String.format("%d %s", 7); // error: missing argument for %s + + String.format("%d", 7, 3); // warning: unused argument 3 + + String.format("{0}", 7); // warning: unused argument 7, because {0} is wrong syntax + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/KeyForExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/KeyForExample.java new file mode 100644 index 0000000000..b3072b72ee --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/KeyForExample.java @@ -0,0 +1,31 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.nullness.qual.KeyFor; + +import java.util.HashMap; +import java.util.Map; + +public class KeyForExample { + + private final Map config = new HashMap<>(); + + KeyForExample() { + + // Here we initialize a map to store + // some config data. + config.put("url", "http://1.2.3.4"); + config.put("name", "foobaz"); + } + + public void dumpPort() { + + // Here, we want to dump the port value stored in the + // config, so we declare that this key has to be + // present in the config map. + // Obviously that will fail because such key is not present + // in the map. + @KeyFor("config") String key = "port"; + System.out.println( config.get(key) ); + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/MonotonicNotNullExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/MonotonicNotNullExample.java new file mode 100644 index 0000000000..c4b9c6afe1 --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/MonotonicNotNullExample.java @@ -0,0 +1,28 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; + +import java.util.Date; + +public class MonotonicNotNullExample { + + // The idea is we need this field to be to lazily initialized, + // so it starts as null but once it becomes not null + // it cannot return null. + // In these cases, we can use @MonotonicNonNull + @MonotonicNonNull private Date firstCall; + + public Date getFirstCall() { + if (firstCall == null) { + firstCall = new Date(); + } + return firstCall; + } + + public void reset() { + // This is reported as error because + // we wrongly set the field back to null. + firstCall = null; + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/NonNullExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/NonNullExample.java new file mode 100644 index 0000000000..c929eea23f --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/NonNullExample.java @@ -0,0 +1,27 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; + +public class NonNullExample { + + // This method's parameter is annotated in order + // to tell the pluggable type system that it can never be null. + private static int countArgs(@NonNull String[] args) { + return args.length; + } + + // This method's parameter is annotated in order + // to tell the pluggable type system that it may be null. + public static void main(@Nullable String[] args) { + + // Here lies a potential error, + // because we pass a potential null reference to a method + // that does not accept nulls. + // The Checker Framework will spot this problem at compile time + // instead of runtime. + System.out.println(countArgs(args)); + + } + +} diff --git a/checker-plugin/src/main/java/com/baeldung/typechecker/RegexExample.java b/checker-plugin/src/main/java/com/baeldung/typechecker/RegexExample.java new file mode 100644 index 0000000000..9503865214 --- /dev/null +++ b/checker-plugin/src/main/java/com/baeldung/typechecker/RegexExample.java @@ -0,0 +1,18 @@ +package com.baeldung.typechecker; + +import org.checkerframework.checker.regex.qual.Regex; + +public class RegexExample { + + // For some reason we want to be sure that this regex + // contains at least one capturing group. + // However, we do an error and we forgot to define such + // capturing group in it. + @Regex(1) private static String findNumbers = "\\d*"; + + public static void main(String[] args) { + String message = "My phone number is +3911223344."; + message.matches(findNumbers); + } + +} diff --git a/core-groovy/README.md b/core-groovy/README.md new file mode 100644 index 0000000000..5954a8ab7e --- /dev/null +++ b/core-groovy/README.md @@ -0,0 +1,4 @@ +# Groovy + +## Relevant articles: + diff --git a/core-groovy/pom.xml b/core-groovy/pom.xml new file mode 100644 index 0000000000..965670e78e --- /dev/null +++ b/core-groovy/pom.xml @@ -0,0 +1,118 @@ + + + 4.0.0 + + core-groovy + 1.0-SNAPSHOT + jar + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + central + http://jcenter.bintray.com + + + + + + org.codehaus.groovy + groovy + 2.4.13 + + + org.codehaus.groovy + groovy-sql + 2.4.13 + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + org.junit.platform + junit-platform-runner + ${junit.platform.version} + test + + + org.hsqldb + hsqldb + 2.4.0 + test + + + + + + + org.codehaus.gmavenplus + gmavenplus-plugin + 1.6 + + + + addSources + addTestSources + compile + compileTests + + + + + + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + maven-failsafe-plugin + 2.19.1 + + + org.junit.platform + junit-platform-surefire-provider + ${junit.platform.version} + + + + + junit5 + + integration-test + verify + + + + **/*Test5.java + + + + + + + + + + UTF-8 + 1.1.2 + 1.1.2 + 1.1.2 + 1.1.2 + 0.15 + 1.5.0 + + 5.0.0 + 1.0.0 + 4.12.0 + 4.12 + + + diff --git a/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy b/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy new file mode 100644 index 0000000000..ac96a55773 --- /dev/null +++ b/core-groovy/src/test/groovy/com/baeldung/groovy/sql/SqlTest.groovy @@ -0,0 +1,229 @@ +package com.baeldung.groovy.sql + +import groovy.sql.GroovyResultSet +import groovy.sql.GroovyRowResult +import groovy.sql.Sql +import groovy.transform.CompileStatic +import static org.junit.Assert.* +import org.junit.Test + +class SqlTest { + + final Map dbConnParams = [url: 'jdbc:hsqldb:mem:testDB', user: 'sa', password: '', driver: 'org.hsqldb.jdbc.JDBCDriver'] + + @Test + void whenNewSqlInstance_thenDbIsAccessed() { + def sql = Sql.newInstance(dbConnParams) + sql.close() + sql.close() + } + + @Test + void whenTableDoesNotExist_thenSelectFails() { + try { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.eachRow('select * from PROJECT') {} + } + + fail("An exception should have been thrown") + } catch (ignored) { + //Ok + } + } + + @Test + void whenTableCreated_thenSelectIsPossible() { + Sql.withInstance(dbConnParams) { Sql sql -> + def result = sql.execute 'create table PROJECT_1 (id integer not null, name varchar(50), url varchar(100))' + + assertEquals(0, sql.updateCount) + assertFalse(result) + + result = sql.execute('select * from PROJECT_1') + + assertTrue(result) + } + } + + @Test + void whenIdentityColumn_thenInsertReturnsNewId() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_2 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + def ids = sql.executeInsert("INSERT INTO PROJECT_2 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") + + assertEquals(0, ids[0][0]) + + ids = sql.executeInsert("INSERT INTO PROJECT_2 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") + + assertEquals(1, ids[0][0]) + } + } + + @Test + void whenUpdate_thenNumberOfAffectedRows() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_3 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_3 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_3 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") + def count = sql.executeUpdate("UPDATE PROJECT_3 SET URL = 'https://' + URL") + + assertEquals(2, count) + } + } + + @Test + void whenEachRow_thenResultSetHasProperties() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_4 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_4 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_4 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") + + sql.eachRow("SELECT * FROM PROJECT_4") { GroovyResultSet rs -> + assertNotNull(rs.name) + assertNotNull(rs.url) + assertNotNull(rs[0]) + assertNotNull(rs[1]) + assertNotNull(rs[2]) + assertEquals(rs.name, rs['name']) + assertEquals(rs.url, rs['url']) + } + } + } + + @Test + void whenPagination_thenSubsetIsReturned() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_5 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") + def rows = sql.rows('SELECT * FROM PROJECT_5 ORDER BY NAME', 1, 1) + + assertEquals(1, rows.size()) + assertEquals('REST with Spring', rows[0].name) + } + } + + @Test + void whenParameters_thenReplacement() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_6 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute('INSERT INTO PROJECT_6 (NAME, URL) VALUES (?, ?)', 'tutorials', 'github.com/eugenp/tutorials') + sql.execute("INSERT INTO PROJECT_6 (NAME, URL) VALUES (:name, :url)", [name: 'REST with Spring', url: 'github.com/eugenp/REST-With-Spring']) + + def rows = sql.rows("SELECT * FROM PROJECT_6 WHERE NAME = 'tutorials'") + + assertEquals(1, rows.size()) + + rows = sql.rows("SELECT * FROM PROJECT_6 WHERE NAME = 'REST with Spring'") + + assertEquals(1, rows.size()) + } + } + + @Test + void whenParametersInGString_thenReplacement() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_7 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.execute "INSERT INTO PROJECT_7 (NAME, URL) VALUES (${'tutorials'}, ${'github.com/eugenp/tutorials'})" + def name = 'REST with Spring' + def url = 'github.com/eugenp/REST-With-Spring' + sql.execute "INSERT INTO PROJECT_7 (NAME, URL) VALUES (${name}, ${url})" + + def rows = sql.rows("SELECT * FROM PROJECT_7 WHERE NAME = 'tutorials'") + + assertEquals(1, rows.size()) + + rows = sql.rows("SELECT * FROM PROJECT_7 WHERE NAME = 'REST with Spring'") + + assertEquals(1, rows.size()) + } + } + + @Test + void whenTransactionRollback_thenNoDataInserted() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.withTransaction { + sql.execute 'create table PROJECT_8 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_8 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_8 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") + sql.rollback() + + def rows = sql.rows("SELECT * FROM PROJECT_8") + + assertEquals(0, rows.size()) + } + } + } + + @Test + void whenTransactionRollbackThenCommit_thenOnlyLastInserted() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.withTransaction { + sql.execute 'create table PROJECT_9 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + sql.rollback() + sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") + sql.rollback() + sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_9 (NAME, URL) VALUES ('REST with Spring', 'https://github.com/eugenp/REST-With-Spring')") + } + + def rows = sql.rows("SELECT * FROM PROJECT_9") + + assertEquals(2, rows.size()) + } + } + + @Test + void whenException_thenTransactionIsRolledBack() { + Sql.withInstance(dbConnParams) { Sql sql -> + try { + sql.withTransaction { + sql.execute 'create table PROJECT_10 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_10 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + throw new Exception('rollback') + } + } catch (ignored) {} + + def rows = sql.rows("SELECT * FROM PROJECT_10") + + assertEquals(0, rows.size()) + } + } + + @Test + void givenCachedConnection_whenException_thenDataIsPersisted() { + Sql.withInstance(dbConnParams) { Sql sql -> + try { + sql.cacheConnection { + sql.execute 'create table PROJECT_11 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_11 (NAME, URL) VALUES ('tutorials', 'https://github.com/eugenp/tutorials')") + throw new Exception('This does not rollback') + } + } catch (ignored) {} + + def rows = sql.rows("SELECT * FROM PROJECT_11") + + assertEquals(1, rows.size()) + } + } + + /*@Test + void whenModifyResultSet_thenDataIsChanged() { + Sql.withInstance(dbConnParams) { Sql sql -> + sql.execute 'create table PROJECT_5 (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))' + sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')") + sql.executeInsert("INSERT INTO PROJECT_5 (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')") + + sql.eachRow("SELECT * FROM PROJECT_5 FOR UPDATE ") { GroovyResultSet rs -> + rs['name'] = "The great ${rs.name}!" as String + rs.updateRow() + } + + sql.eachRow("SELECT * FROM PROJECT_5") { GroovyResultSet rs -> + assertTrue(rs.name.startsWith('The great ')) + } + } + }*/ + +} diff --git a/core-java-8/README.md b/core-java-8/README.md index 9260e3d447..1b5208961d 100644 --- a/core-java-8/README.md +++ b/core-java-8/README.md @@ -40,3 +40,4 @@ - [Efficient Word Frequency Calculator in Java](http://www.baeldung.com/java-word-frequency) - [Primitive Type Streams in Java 8](http://www.baeldung.com/java-8-primitive-streams) - [Fail-Safe Iterator vs Fail-Fast Iterator](http://www.baeldung.com/java-fail-safe-vs-fail-fast-iterator) +- [Shuffling Collections In Java](http://www.baeldung.com/java-shuffle-collection) diff --git a/core-java-8/src/test/java/com/baeldung/shufflingcollections/ShufflingCollectionsUnitTest.java b/core-java-8/src/test/java/com/baeldung/shufflingcollections/ShufflingCollectionsUnitTest.java index 4823c7178a..d013907c9a 100644 --- a/core-java-8/src/test/java/com/baeldung/shufflingcollections/ShufflingCollectionsUnitTest.java +++ b/core-java-8/src/test/java/com/baeldung/shufflingcollections/ShufflingCollectionsUnitTest.java @@ -22,7 +22,7 @@ public class ShufflingCollectionsUnitTest { } @Test - public void whenShufflingMapKeys_thenValuesAreShuffled() { + public void whenShufflingMapEntries_thenValuesAreShuffled() { Map studentsById = new HashMap<>(); studentsById.put(1, "Foo"); studentsById.put(2, "Bar"); @@ -32,12 +32,12 @@ public class ShufflingCollectionsUnitTest { System.out.println("Students before shuffling:"); System.out.println(studentsById.values()); - List shuffledStudentIds = new ArrayList<>(studentsById.keySet()); - Collections.shuffle(shuffledStudentIds); + List> shuffledStudentEntries = new ArrayList<>(studentsById.entrySet()); + Collections.shuffle(shuffledStudentEntries); - List shuffledStudents = shuffledStudentIds.stream() - .map(id -> studentsById.get(id)) - .collect(Collectors.toList()); + List shuffledStudents = shuffledStudentEntries.stream() + .map(Map.Entry::getValue) + .collect(Collectors.toList()); System.out.println("Students after shuffling"); System.out.println(shuffledStudents); diff --git a/core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadTest.java b/core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadManualTest.java similarity index 97% rename from core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadTest.java rename to core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadManualTest.java index af54d6932e..9ea40824ca 100644 --- a/core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadTest.java +++ b/core-java-concurrency/src/test/java/com/baeldung/concurrent/stopping/StopThreadManualTest.java @@ -10,7 +10,7 @@ import org.junit.Test; import com.jayway.awaitility.Awaitility; -public class StopThreadTest { +public class StopThreadManualTest { @Test public void whenStoppedThreadIsStopped() throws InterruptedException { diff --git a/core-java/README.md b/core-java/README.md index ed60db855c..b160d2271e 100644 --- a/core-java/README.md +++ b/core-java/README.md @@ -127,3 +127,4 @@ - [Polymorphism in Java](http://www.baeldung.com/java-polymorphism) - [Recursion In Java](http://www.baeldung.com/java-recursion) - [A Guide to the finalize Method in Java](http://www.baeldung.com/java-finalize) +- [Compiling Java *.class Files with javac](http://www.baeldung.com/javac) diff --git a/core-java/pom.xml b/core-java/pom.xml index 5c1e9fcad0..e2983de9dd 100644 --- a/core-java/pom.xml +++ b/core-java/pom.xml @@ -78,6 +78,11 @@ jackson-databind ${jackson.version} + + com.google.code.gson + gson + ${gson.version} + @@ -468,6 +473,7 @@ 2.8.5 + 2.8.2 1.7.21 diff --git a/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java b/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java new file mode 100644 index 0000000000..c44e863776 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/classloader/CustomClassLoader.java @@ -0,0 +1,29 @@ +package com.baeldung.classloader; + +import java.io.*; + +public class CustomClassLoader extends ClassLoader { + + + public Class getClass(String name) throws ClassNotFoundException { + byte[] b = loadClassFromFile(name); + return defineClass(name, b, 0, b.length); + } + + private byte[] loadClassFromFile(String fileName) { + InputStream inputStream = getClass().getClassLoader().getResourceAsStream( + fileName.replace('.', File.separatorChar) + ".class"); + byte[] buffer; + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + int nextValue = 0; + try { + while ( (nextValue = inputStream.read()) != -1 ) { + byteStream.write(nextValue); + } + } catch (IOException e) { + e.printStackTrace(); + } + buffer = byteStream.toByteArray(); + return buffer; + } +} diff --git a/core-java/src/main/java/com/baeldung/classloader/PrintClassLoader.java b/core-java/src/main/java/com/baeldung/classloader/PrintClassLoader.java new file mode 100644 index 0000000000..09ee68bf6e --- /dev/null +++ b/core-java/src/main/java/com/baeldung/classloader/PrintClassLoader.java @@ -0,0 +1,22 @@ +package com.baeldung.classloader; + +import com.sun.javafx.util.Logging; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; + +public class PrintClassLoader { + + public void printClassLoaders() throws ClassNotFoundException { + + System.out.println("Classloader of this class:" + PrintClassLoader.class.getClassLoader()); + System.out.println("Classloader of Logging:" + Logging.class.getClassLoader()); + System.out.println("Classloader of ArrayList:" + ArrayList.class.getClassLoader()); + + } +} diff --git a/core-java/src/main/java/com/baeldung/deepcopy/Address.java b/core-java/src/main/java/com/baeldung/deepcopy/Address.java new file mode 100644 index 0000000000..4e010ea92b --- /dev/null +++ b/core-java/src/main/java/com/baeldung/deepcopy/Address.java @@ -0,0 +1,59 @@ +package com.baeldung.deepcopy; + +import java.io.Serializable; + +public class Address implements Serializable, Cloneable { + + @Override + public Object clone() { + try { + return (Address) super.clone(); + } catch (CloneNotSupportedException e) { + return new Address(this.street, this.getCity(), this.getCountry()); + } + } + + private static final long serialVersionUID = 1740913841244949416L; + private String street; + private String city; + + private String country; + + public Address(Address that) { + this(that.getStreet(), that.getCity(), that.getCountry()); + } + + public Address(String street, String city, String country) { + this.street = street; + this.city = city; + this.country = country; + } + + public Address() { + } + + public String getStreet() { + return street; + } + + public String getCity() { + return city; + } + + public String getCountry() { + return country; + } + + public void setStreet(String street) { + this.street = street; + } + + public void setCity(String city) { + this.city = city; + } + + public void setCountry(String country) { + this.country = country; + } +} + diff --git a/core-java/src/main/java/com/baeldung/deepcopy/User.java b/core-java/src/main/java/com/baeldung/deepcopy/User.java new file mode 100644 index 0000000000..329cfc6b27 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/deepcopy/User.java @@ -0,0 +1,48 @@ +package com.baeldung.deepcopy; + +import java.io.Serializable; + +public class User implements Serializable, Cloneable { + + private static final long serialVersionUID = -3427002229954777557L; + private String firstName; + private String lastName; + private Address address; + + public User(String firstName, String lastName, Address address) { + this.firstName = firstName; + this.lastName = lastName; + this.address = address; + } + + public User(User that) { + this(that.getFirstName(), that.getLastName(), new Address(that.getAddress())); + } + + public User() { + } + + @Override + public Object clone() { + User user; + try { + user = (User) super.clone(); + } catch (CloneNotSupportedException e) { + user = new User(this.getFirstName(), this.getLastName(), this.getAddress()); + } + user.address = (Address) this.address.clone(); + return user; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public Address getAddress() { + return address; + } +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Car.java b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Car.java new file mode 100644 index 0000000000..50f62cafaa --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Car.java @@ -0,0 +1,85 @@ +package com.baeldung.designpatterns.flyweight; + +import java.awt.Color; + +import javax.annotation.concurrent.Immutable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represents a car. This class is immutable. + * + * @author Donato Rimenti + */ +@Immutable +public class Car implements Vehicle { + + /** + * Logger. + */ + private final static Logger LOG = LoggerFactory.getLogger(Car.class); + + /** + * The car's engine. + */ + private Engine engine; + + /** + * The car's color. + */ + private Color color; + + /** + * Instantiates a new Car. + * + * @param engine + * the {@link #engine} + * @param color + * the {@link #color} + */ + public Car(Engine engine, Color color) { + this.engine = engine; + this.color = color; + + // Building a new car is a very expensive operation! + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + LOG.error("Error while creating a new car", e); + } + } + + /* + * (non-Javadoc) + * + * @see com.baeldung.designpatterns.flyweight.Vehicle#start() + */ + @Override + public void start() { + LOG.info("Car is starting!"); + engine.start(); + } + + /* + * (non-Javadoc) + * + * @see com.baeldung.designpatterns.flyweight.Vehicle#stop() + */ + @Override + public void stop() { + LOG.info("Car is stopping!"); + engine.stop(); + } + + /* + * (non-Javadoc) + * + * @see com.baeldung.designpatterns.flyweight.Vehicle#getColor() + */ + @Override + public Color getColor() { + return this.color; + } + +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Engine.java b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Engine.java new file mode 100644 index 0000000000..05d9ca98b8 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Engine.java @@ -0,0 +1,31 @@ +package com.baeldung.designpatterns.flyweight; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Engine for a vehicle. + * + * @author Donato Rimenti + */ +public class Engine { + + /** + * Logger. + */ + private final static Logger LOG = LoggerFactory.getLogger(Engine.class); + + /** + * Starts the engine. + */ + public void start() { + LOG.info("Engine is starting!"); + } + + /** + * Stops the engine. + */ + public void stop() { + LOG.info("Engine is stopping!"); + } +} diff --git a/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Vehicle.java b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Vehicle.java new file mode 100644 index 0000000000..c285f9fcff --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/Vehicle.java @@ -0,0 +1,29 @@ +package com.baeldung.designpatterns.flyweight; + +import java.awt.Color; + +/** + * Interface for a vehicle. + * + * @author Donato Rimenti + */ +public interface Vehicle { + + /** + * Starts the vehicle. + */ + public void start(); + + /** + * Stops the vehicle. + */ + public void stop(); + + /** + * Gets the color of the vehicle. + * + * @return the color of the vehicle + */ + public Color getColor(); + +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/designpatterns/flyweight/VehicleFactory.java b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/VehicleFactory.java new file mode 100644 index 0000000000..2854b7dab1 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/designpatterns/flyweight/VehicleFactory.java @@ -0,0 +1,45 @@ +package com.baeldung.designpatterns.flyweight; + +import java.awt.Color; +import java.util.HashMap; +import java.util.Map; + +/** + * Factory which implements the Flyweight pattern to return an existing vehicle + * if present or a new one otherwise. + * + * @author Donato Rimenti + */ +public class VehicleFactory { + + /** + * Stores the already created vehicles. + */ + private static Map vehiclesCache = new HashMap(); + + /** + * Private constructor to prevent this class instantiation. + */ + private VehicleFactory() { + } + + /** + * Returns a vehicle of the same color passed as argument. If that vehicle + * was already created by this factory, that vehicle is returned, otherwise + * a new one is created and returned. + * + * @param color + * the color of the vehicle to return + * @return a vehicle of the specified color + */ + public static Vehicle createVehicle(Color color) { + // Looks for the requested vehicle into the cache. + // If the vehicle doesn't exist, a new one is created. + Vehicle newVehicle = vehiclesCache.computeIfAbsent(color, newColor -> { + // Creates the new car. + Engine newEngine = new Engine(); + return new Car(newEngine, newColor); + }); + return newVehicle; + } +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/ArmoredCar.java b/core-java/src/main/java/com/baeldung/inheritance/ArmoredCar.java new file mode 100644 index 0000000000..b6bb5181b8 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/ArmoredCar.java @@ -0,0 +1,43 @@ +package com.baeldung.inheritance; + +public class ArmoredCar extends Car implements Floatable, Flyable{ + private int bulletProofWindows; + private String model; + + public void remoteStartCar() { + // this vehicle can be started by using a remote control + } + + public String registerModel() { + return model; + } + + public String getAValue() { + return super.model; // returns value of model defined in base class Car + // return this.model; // will return value of model defined in ArmoredCar + // return model; // will return value of model defined in ArmoredCar + } + + public static String msg() { + // return super.msg(); // this won't compile. + return "ArmoredCar"; + } + + @Override + public void floatOnWater() { + System.out.println("I can float!"); + } + + @Override + public void fly() { + System.out.println("I can fly!"); + } + + public void aMethod() { + // System.out.println(duration); // Won't compile + System.out.println(Floatable.duration); // outputs 10 + System.out.println(Flyable.duration); // outputs 20 + } + + +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/BMW.java b/core-java/src/main/java/com/baeldung/inheritance/BMW.java new file mode 100644 index 0000000000..8ad3bb683f --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/BMW.java @@ -0,0 +1,12 @@ +package com.baeldung.inheritance; + +public class BMW extends Car { + public BMW() { + super(5, "BMW"); + } + + @Override + public String toString() { + return model; + } +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/Car.java b/core-java/src/main/java/com/baeldung/inheritance/Car.java new file mode 100644 index 0000000000..21ea9ea569 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/Car.java @@ -0,0 +1,32 @@ +package com.baeldung.inheritance; + +public class Car { + private final int DEFAULT_WHEEL_COUNT = 5; + private final String DEFAULT_MODEL = "Basic"; + + protected int wheels; + protected String model; + + public Car() { + this.wheels = DEFAULT_WHEEL_COUNT; + this.model = DEFAULT_MODEL; + } + + public Car(int wheels, String model) { + this.wheels = wheels; + this.model = model; + } + + public void start() { + // Check essential parts + // If okay, start. + } + public static int count = 10; + public static String msg() { + return "Car"; + } + + public String toString() { + return model; + } +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/inheritance/Employee.java b/core-java/src/main/java/com/baeldung/inheritance/Employee.java new file mode 100644 index 0000000000..599a1d7331 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/Employee.java @@ -0,0 +1,15 @@ +package com.baeldung.inheritance; + +public class Employee { + private String name; + private Car car; + + public Employee(String name, Car car) { + this.name = name; + this.car = car; + } + + public Car getCar() { + return car; + } +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/inheritance/Floatable.java b/core-java/src/main/java/com/baeldung/inheritance/Floatable.java new file mode 100644 index 0000000000..c0b456dffb --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/Floatable.java @@ -0,0 +1,10 @@ +package com.baeldung.inheritance; + +public interface Floatable { + int duration = 10; + void floatOnWater(); + + default void repair() { + System.out.println("Repairing Floatable object"); + } +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/Flyable.java b/core-java/src/main/java/com/baeldung/inheritance/Flyable.java new file mode 100644 index 0000000000..cb8244cf5b --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/Flyable.java @@ -0,0 +1,13 @@ +package com.baeldung.inheritance; + +public interface Flyable { + int duration = 10; + void fly(); + + /* + * Commented + */ + //default void repair() { + // System.out.println("Repairing Flyable object"); + //} +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/SpaceCar.java b/core-java/src/main/java/com/baeldung/inheritance/SpaceCar.java new file mode 100644 index 0000000000..8c23b26da9 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/SpaceCar.java @@ -0,0 +1,18 @@ +package com.baeldung.inheritance; + +public class SpaceCar extends Car implements SpaceTraveller { + @Override + public void floatOnWater() { + System.out.println("SpaceCar floating!"); + } + + @Override + public void fly() { + System.out.println("SpaceCar flying!"); + } + + @Override + public void remoteControl() { + System.out.println("SpaceCar being controlled remotely!"); + } +} diff --git a/core-java/src/main/java/com/baeldung/inheritance/SpaceTraveller.java b/core-java/src/main/java/com/baeldung/inheritance/SpaceTraveller.java new file mode 100644 index 0000000000..9b66441791 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/inheritance/SpaceTraveller.java @@ -0,0 +1,6 @@ +package com.baeldung.inheritance; + +public interface SpaceTraveller extends Floatable, Flyable { + int duration = 10; + void remoteControl(); +} \ No newline at end of file diff --git a/core-java/src/main/java/com/baeldung/recursion/BinaryNode.java b/core-java/src/main/java/com/baeldung/recursion/BinaryNode.java new file mode 100644 index 0000000000..0c3f0ecc40 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/recursion/BinaryNode.java @@ -0,0 +1,31 @@ +package com.baeldung.recursion; + +public class BinaryNode { + int value; + BinaryNode left; + BinaryNode right; + + public BinaryNode(int value){ + this.value = value; + } + + public int getValue() { + return value; + } + public void setValue(int value) { + this.value = value; + } + public BinaryNode getLeft() { + return left; + } + public void setLeft(BinaryNode left) { + this.left = left; + } + public BinaryNode getRight() { + return right; + } + public void setRight(BinaryNode right) { + this.right = right; + } + +} diff --git a/core-java/src/main/java/com/baeldung/recursion/RecursionExample.java b/core-java/src/main/java/com/baeldung/recursion/RecursionExample.java new file mode 100644 index 0000000000..649c0e0587 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/recursion/RecursionExample.java @@ -0,0 +1,64 @@ +package com.baeldung.recursion; + +public class RecursionExample { + + public int sum(int n){ + if (n >= 1){ + return sum(n - 1) + n; + } + return n; + } + + public int tailSum(int currentSum, int n){ + if (n <= 1) { + return currentSum + n; + } + return tailSum(currentSum + n, n - 1); + } + + public int iterativeSum(int n){ + int sum = 0; + if(n < 0){ + return -1; + } + for(int i=0; i<=n; i++){ + sum += i; + } + return sum; + } + + public int powerOf10(int n){ + if (n == 0){ + return 1; + } + return powerOf10(n-1)*10; + } + + public int fibonacci(int n){ + if (n <=1 ){ + return n; + } + return fibonacci(n-1) + fibonacci(n-2); + } + + public String toBinary(int n){ + if (n <= 1 ){ + return String.valueOf(n); + } + return toBinary(n / 2) + String.valueOf(n % 2); + } + + public int calculateTreeHeight(BinaryNode root){ + if (root!= null){ + if (root.getLeft() != null || root.getRight() != null){ + return 1 + max(calculateTreeHeight(root.left) , calculateTreeHeight(root.right)); + } + } + return 0; + } + + public int max(int a,int b){ + return a>b ? a:b; + } + +} diff --git a/core-java/src/main/java/com/baeldung/resourcebundle/ExampleControl.java b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleControl.java new file mode 100644 index 0000000000..88ce36c27f --- /dev/null +++ b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleControl.java @@ -0,0 +1,15 @@ +package com.baeldung.resourcebundle; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; + +public class ExampleControl extends ResourceBundle.Control { + + @Override + public List getCandidateLocales(String s, Locale locale) { + return Arrays.asList(new Locale("pl", "PL")); + } + +} diff --git a/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource.java b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource.java new file mode 100644 index 0000000000..52ccc80f52 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource.java @@ -0,0 +1,14 @@ +package com.baeldung.resourcebundle; + +import java.util.ListResourceBundle; + +public class ExampleResource extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "greeting", "hello" } + }; + } + +} diff --git a/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl.java b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl.java new file mode 100644 index 0000000000..7d4f11a5d3 --- /dev/null +++ b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl.java @@ -0,0 +1,15 @@ +package com.baeldung.resourcebundle; + +import java.util.ListResourceBundle; + +public class ExampleResource_pl extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "greeting", "cześć" }, + { "language", "polish" }, + }; + } + +} diff --git a/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl_PL.java b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl_PL.java new file mode 100644 index 0000000000..252bfcb9cf --- /dev/null +++ b/core-java/src/main/java/com/baeldung/resourcebundle/ExampleResource_pl_PL.java @@ -0,0 +1,17 @@ +package com.baeldung.resourcebundle; + +import java.math.BigDecimal; +import java.util.ListResourceBundle; + +public class ExampleResource_pl_PL extends ListResourceBundle { + + @Override + protected Object[][] getContents() { + return new Object[][] { + { "currency", "polish zloty" }, + { "toUsdRate", new BigDecimal("3.401") }, + { "cities", new String[] { "Warsaw", "Cracow" } } + }; + } + +} diff --git a/core-java/src/main/resources/resourcebundle/resource.properties b/core-java/src/main/resources/resourcebundle/resource.properties new file mode 100644 index 0000000000..edeae3ef4b --- /dev/null +++ b/core-java/src/main/resources/resourcebundle/resource.properties @@ -0,0 +1,6 @@ +# Buttons +cancelButton=cancel +continueButton continue + +! Labels +helloLabel:hello diff --git a/core-java/src/main/resources/resourcebundle/resource_en.properties b/core-java/src/main/resources/resourcebundle/resource_en.properties new file mode 100644 index 0000000000..5d72b65e2f --- /dev/null +++ b/core-java/src/main/resources/resourcebundle/resource_en.properties @@ -0,0 +1 @@ +deleteButton=delete \ No newline at end of file diff --git a/core-java/src/main/resources/resourcebundle/resource_pl_PL.properties b/core-java/src/main/resources/resourcebundle/resource_pl_PL.properties new file mode 100644 index 0000000000..37dea822ad --- /dev/null +++ b/core-java/src/main/resources/resourcebundle/resource_pl_PL.properties @@ -0,0 +1,3 @@ +backButton=cofnij +helloLabel=cze\u015b\u0107 +helloLabelNoEncoding=cześć \ No newline at end of file diff --git a/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderTest.java b/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderTest.java new file mode 100644 index 0000000000..9f3c751805 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/classloader/CustomClassLoaderTest.java @@ -0,0 +1,23 @@ +package com.baeldung.classloader; + +import org.junit.Test; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class CustomClassLoaderTest { + + @Test + public void customLoader() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { + + CustomClassLoader customClassLoader = new CustomClassLoader(); + Class c = customClassLoader.getClass(PrintClassLoader.class.getName()); + + Object ob = c.newInstance(); + + Method md = c.getMethod("printClassLoaders"); + md.invoke(ob); + + } + +} diff --git a/core-java/src/test/java/com/baeldung/classloader/PrintClassLoaderTest.java b/core-java/src/test/java/com/baeldung/classloader/PrintClassLoaderTest.java new file mode 100644 index 0000000000..f44a5cef09 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/classloader/PrintClassLoaderTest.java @@ -0,0 +1,14 @@ +package com.baeldung.classloader; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class PrintClassLoaderTest { + @Test(expected = ClassNotFoundException.class) + public void givenAppClassLoader_whenParentClassLoader_thenClassNotFoundException() throws Exception { + PrintClassLoader sampleClassLoader = (PrintClassLoader) Class.forName(PrintClassLoader.class.getName()).newInstance(); + sampleClassLoader.printClassLoaders(); + Class.forName(PrintClassLoader.class.getName(), true, PrintClassLoader.class.getClassLoader().getParent()); + } +} \ No newline at end of file diff --git a/core-java/src/test/java/com/baeldung/deepcopy/DeepCopyUnitTest.java b/core-java/src/test/java/com/baeldung/deepcopy/DeepCopyUnitTest.java new file mode 100644 index 0000000000..196b69fbf7 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/deepcopy/DeepCopyUnitTest.java @@ -0,0 +1,128 @@ +package com.baeldung.deepcopy; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; + +import org.apache.commons.lang.SerializationUtils; +import org.junit.Ignore; +import org.junit.Test; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; + +public class DeepCopyUnitTest { + + @Test + public void whenCreatingDeepCopyWithCopyConstructor_thenObjectsShouldNotBeSame() { + + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + + User deepCopy = new User(pm); + + assertThat(deepCopy).isNotSameAs(pm); + } + + @Test + public void whenModifyingOriginalObject_thenConstructorCopyShouldNotChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + User deepCopy = new User(pm); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + public void whenModifyingOriginalObject_thenCloneCopyShouldNotChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + User deepCopy = (User) pm.clone(); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + public void whenModifyingOriginalObject_thenCommonsCloneShouldNotChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + User deepCopy = (User) SerializationUtils.clone(pm); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + public void whenModifyingOriginalObject_thenGsonCloneShouldNotChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + Gson gson = new Gson(); + User deepCopy = gson.fromJson(gson.toJson(pm), User.class); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + public void whenModifyingOriginalObject_thenJacksonCopyShouldNotChange() throws IOException { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + ObjectMapper objectMapper = new ObjectMapper(); + User deepCopy = objectMapper.readValue(objectMapper.writeValueAsString(pm), User.class); + + address.setCountry("Great Britain"); + + assertThat(deepCopy.getAddress().getCountry()).isNotEqualTo(pm.getAddress().getCountry()); + } + + @Test + @Ignore + public void whenMakingCopies_thenShowHowLongEachMethodTakes() throws CloneNotSupportedException, IOException { + int times = 1000000; + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + + long start = System.currentTimeMillis(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = (User) SerializationUtils.clone(pm); + } + long end = System.currentTimeMillis(); + System.out.println("Cloning with Apache Commons Lang took " + (end - start) + " milliseconds."); + + start = System.currentTimeMillis(); + Gson gson = new Gson(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = gson.fromJson(gson.toJson(pm), User.class); + } + end = System.currentTimeMillis(); + System.out.println("Cloning with Gson took " + (end - start) + " milliseconds."); + + start = System.currentTimeMillis(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = new User(pm); + } + end = System.currentTimeMillis(); + System.out.println("Cloning with the copy constructor took " + (end - start) + " milliseconds."); + + start = System.currentTimeMillis(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = (User) pm.clone(); + } + end = System.currentTimeMillis(); + System.out.println("Cloning with Cloneable interface took " + (end - start) + " milliseconds."); + + start = System.currentTimeMillis(); + ObjectMapper objectMapper = new ObjectMapper(); + for (int i = 0; i < times; i++) { + User primeMinisterClone = objectMapper.readValue(objectMapper.writeValueAsString(pm), User.class); + } + end = System.currentTimeMillis(); + System.out.println("Cloning with Jackson took " + (end - start) + " milliseconds."); + } +} diff --git a/core-java/src/test/java/com/baeldung/deepcopy/ShallowCopyUnitTest.java b/core-java/src/test/java/com/baeldung/deepcopy/ShallowCopyUnitTest.java new file mode 100644 index 0000000000..57660fadf1 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/deepcopy/ShallowCopyUnitTest.java @@ -0,0 +1,33 @@ +package com.baeldung.deepcopy; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +public class ShallowCopyUnitTest { + + + @Test + public void whenShallowCopying_thenObjectsShouldNotBeSame() { + + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + + User shallowCopy = new User(pm.getFirstName(), pm.getLastName(), pm.getAddress()); + + assertThat(shallowCopy) + .isNotSameAs(pm); + } + + @Test + public void whenModifyingOriginalObject_thenCopyShouldChange() { + Address address = new Address("Downing St 10", "London", "England"); + User pm = new User("Prime", "Minister", address); + User shallowCopy = new User(pm.getFirstName(), pm.getLastName(), pm.getAddress()); + + address.setCountry("Great Britain"); + + assertThat(shallowCopy.getAddress().getCountry()) + .isEqualTo(pm.getAddress().getCountry()); + } +} diff --git a/core-java/src/test/java/com/baeldung/designpatterns/flyweight/FlyweightUnitTest.java b/core-java/src/test/java/com/baeldung/designpatterns/flyweight/FlyweightUnitTest.java new file mode 100644 index 0000000000..645e2fd459 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/designpatterns/flyweight/FlyweightUnitTest.java @@ -0,0 +1,42 @@ +package com.baeldung.designpatterns.flyweight; + +import java.awt.Color; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Unit test for {@link VehicleFactory}. + * + * @author Donato Rimenti + */ +public class FlyweightUnitTest { + + /** + * Checks that when the {@link VehicleFactory} is asked to provide two + * vehicles of different colors, the objects returned are different. + */ + @Test + public void givenDifferentFlyweightObjects_whenEquals_thenFalse() { + Vehicle blackVehicle = VehicleFactory.createVehicle(Color.BLACK); + Vehicle blueVehicle = VehicleFactory.createVehicle(Color.BLUE); + + Assert.assertNotNull("Object returned by the factory is null!", blackVehicle); + Assert.assertNotNull("Object returned by the factory is null!", blueVehicle); + Assert.assertNotEquals("Objects returned by the factory are equals!", blackVehicle, blueVehicle); + } + + /** + * Checks that when the {@link VehicleFactory} is asked to provide two + * vehicles of the same colors, the same object is returned twice. + */ + @Test + public void givenSameFlyweightObjects_whenEquals_thenTrue() { + Vehicle blackVehicle = VehicleFactory.createVehicle(Color.BLACK); + Vehicle anotherBlackVehicle = VehicleFactory.createVehicle(Color.BLACK); + + Assert.assertNotNull("Object returned by the factory is null!", blackVehicle); + Assert.assertNotNull("Object returned by the factory is null!", anotherBlackVehicle); + Assert.assertEquals("Objects returned by the factory are not equals!", blackVehicle, anotherBlackVehicle); + } +} diff --git a/core-java/src/test/java/com/baeldung/inheritance/AppTest.java b/core-java/src/test/java/com/baeldung/inheritance/AppTest.java new file mode 100644 index 0000000000..1235761aba --- /dev/null +++ b/core-java/src/test/java/com/baeldung/inheritance/AppTest.java @@ -0,0 +1,46 @@ +package com.baeldung.inheritance; + +import com.baeldung.inheritance.*; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +public class AppTest extends TestCase { + + public AppTest(String testName) { + super( testName ); + } + + public static Test suite() { + return new TestSuite(AppTest.class); + } + + @SuppressWarnings("static-access") + public void testStaticMethodUsingBaseClassVariable() { + Car first = new ArmoredCar(); + assertEquals("Car", first.msg()); + } + + @SuppressWarnings("static-access") + public void testStaticMethodUsingDerivedClassVariable() { + ArmoredCar second = new ArmoredCar(); + assertEquals("ArmoredCar", second.msg()); + } + + public void testAssignArmoredCarToCar() { + Employee e1 = new Employee("Shreya", new ArmoredCar()); + assertNotNull(e1.getCar()); + } + + public void testAssignSpaceCarToCar() { + Employee e2 = new Employee("Paul", new SpaceCar()); + assertNotNull(e2.getCar()); + } + + public void testBMWToCar() { + Employee e3 = new Employee("Pavni", new BMW()); + assertNotNull(e3.getCar()); + } + +} diff --git a/core-java/src/test/java/com/baeldung/recursion/RecursionExampleTest.java b/core-java/src/test/java/com/baeldung/recursion/RecursionExampleTest.java new file mode 100644 index 0000000000..c65be24240 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/recursion/RecursionExampleTest.java @@ -0,0 +1,61 @@ +package com.baeldung.recursion; + +import org.junit.Assert; +import org.junit.Test; + +public class RecursionExampleTest { + + RecursionExample recursion = new RecursionExample(); + + @Test + public void testPowerOf10() { + int p0 = recursion.powerOf10(0); + int p1 = recursion.powerOf10(1); + int p4 = recursion.powerOf10(4); + + Assert.assertEquals(1, p0); + Assert.assertEquals(10, p1); + Assert.assertEquals(10000, p4); + } + + @Test + public void testFibonacci() { + int n0 = recursion.fibonacci(0); + int n1 = recursion.fibonacci(1); + int n7 = recursion.fibonacci(7); + + Assert.assertEquals(0, n0); + Assert.assertEquals(1, n1); + Assert.assertEquals(13, n7); + } + + @Test + public void testToBinary() { + String b0 = recursion.toBinary(0); + String b1 = recursion.toBinary(1); + String b10 = recursion.toBinary(10); + + Assert.assertEquals("0", b0); + Assert.assertEquals("1", b1); + Assert.assertEquals("1010", b10); + } + + @Test + public void testCalculateTreeHeight() { + BinaryNode root = new BinaryNode(1); + root.setLeft(new BinaryNode(1)); + root.setRight(new BinaryNode(1)); + + root.getLeft().setLeft(new BinaryNode(1)); + root.getLeft().getLeft().setRight(new BinaryNode(1)); + root.getLeft().getLeft().getRight().setLeft(new BinaryNode(1)); + + root.getRight().setLeft(new BinaryNode(1)); + root.getRight().getLeft().setRight(new BinaryNode(1)); + + int height = recursion.calculateTreeHeight(root); + + Assert.assertEquals(4, height); + } + +} diff --git a/core-java/src/test/java/com/baeldung/resourcebundle/ExampleResourceUnitTest.java b/core-java/src/test/java/com/baeldung/resourcebundle/ExampleResourceUnitTest.java new file mode 100644 index 0000000000..1ce4f1bb8f --- /dev/null +++ b/core-java/src/test/java/com/baeldung/resourcebundle/ExampleResourceUnitTest.java @@ -0,0 +1,39 @@ +package com.baeldung.resourcebundle; + +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.Locale; +import java.util.ResourceBundle; + +import static org.junit.Assert.*; + +public class ExampleResourceUnitTest { + + @Test + public void whenGetBundleExampleResourceForLocalePlPl_thenItShouldInheritPropertiesGreetingAndLanguage() { + Locale plLocale = new Locale("pl", "PL"); + + ResourceBundle exampleBundle = ResourceBundle.getBundle("com.baeldung.resourcebundle.ExampleResource", plLocale); + + assertTrue(exampleBundle.keySet() + .containsAll(Arrays.asList("toUsdRate", "cities", "greeting", "currency", "language"))); + assertEquals(exampleBundle.getString("greeting"), "cześć"); + assertEquals(exampleBundle.getObject("toUsdRate"), new BigDecimal("3.401")); + assertArrayEquals(exampleBundle.getStringArray("cities"), new String[] { "Warsaw", "Cracow" }); + } + + @Test + public void whenGetBundleExampleResourceForLocaleUs_thenItShouldContainOnlyGreeting() { + Locale usLocale = Locale.US; + + ResourceBundle exampleBundle = ResourceBundle.getBundle("com.baeldung.resourcebundle.ExampleResource", usLocale); + + assertFalse(exampleBundle.keySet() + .containsAll(Arrays.asList("toUsdRate", "cities", "currency", "language"))); + assertTrue(exampleBundle.keySet() + .containsAll(Arrays.asList("greeting"))); + } + +} diff --git a/core-java/src/test/java/com/baeldung/resourcebundle/PropertyResourceUnitTest.java b/core-java/src/test/java/com/baeldung/resourcebundle/PropertyResourceUnitTest.java new file mode 100644 index 0000000000..4da71567e1 --- /dev/null +++ b/core-java/src/test/java/com/baeldung/resourcebundle/PropertyResourceUnitTest.java @@ -0,0 +1,62 @@ +package com.baeldung.resourcebundle; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Locale; +import java.util.ResourceBundle; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class PropertyResourceUnitTest { + + @Test + public void givenLocaleUsAsDefualt_whenGetBundleForLocalePlPl_thenItShouldContain3ButtonsAnd1Label() { + Locale.setDefault(Locale.US); + + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("pl", "PL")); + + assertTrue(bundle.keySet() + .containsAll(Arrays.asList("backButton", "helloLabel", "cancelButton", "continueButton", "helloLabelNoEncoding"))); + } + + @Test + public void givenLocaleUsAsDefualt_whenGetBundleForLocaleFrFr_thenItShouldContainKeys1To3AndKey4() { + Locale.setDefault(Locale.US); + + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("fr", "FR")); + + assertTrue(bundle.keySet() + .containsAll(Arrays.asList("deleteButton", "helloLabel", "cancelButton", "continueButton"))); + } + + @Test + public void givenLocaleChinaAsDefualt_whenGetBundleForLocaleFrFr_thenItShouldOnlyContainKeys1To3() { + Locale.setDefault(Locale.CHINA); + + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("fr", "FR")); + + assertTrue(bundle.keySet() + .containsAll(Arrays.asList("continueButton", "helloLabel", "cancelButton"))); + } + + @Test + public void givenLocaleChinaAsDefualt_whenGetBundleForLocaleFrFrAndExampleControl_thenItShouldOnlyContainKey5() { + Locale.setDefault(Locale.CHINA); + + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("fr", "FR"), new ExampleControl()); + + assertTrue(bundle.keySet() + .containsAll(Arrays.asList("backButton", "helloLabel"))); + } + + @Test + public void givenValuesDifferentlyEncoded_whenGetBundleForLocalePlPl_thenItShouldContain3ButtonsAnd1Label() { + ResourceBundle bundle = ResourceBundle.getBundle("resourcebundle.resource", new Locale("pl", "PL")); + + assertEquals(bundle.getString("helloLabel"), "cześć"); + assertEquals(bundle.getString("helloLabelNoEncoding"), "czeÅ\u009BÄ\u0087"); + } + +} diff --git a/core-kotlin/README.md b/core-kotlin/README.md index 5908d480b7..1c64817815 100644 --- a/core-kotlin/README.md +++ b/core-kotlin/README.md @@ -17,4 +17,4 @@ - [Sealed Classes in Kotlin](http://www.baeldung.com/kotlin-sealed-classes) - [JUnit 5 for Kotlin Developers](http://www.baeldung.com/junit-5-kotlin) - [Extension Methods in Kotlin](http://www.baeldung.com/kotlin-extension-methods) - +- [Infix Functions in Kotlin](http://www.baeldung.com/kotlin-infix-functions) diff --git a/google-cloud/README.md b/google-cloud/README.md new file mode 100644 index 0000000000..6022796a0e --- /dev/null +++ b/google-cloud/README.md @@ -0,0 +1,16 @@ +## Google Cloud Tutorial Project + +### Relevant Article: +- [Intro to Google Cloud Storage With Java](http://www.baeldung.com/intro-to-google-cloud-storage-with-java/) + +### Overview +This Maven project contains the Java code for the article linked above. + +### Package Organization +Java classes for the intro tutorial are in the org.baeldung.google.cloud package. Please note that Google Cloud requires +a user account and credentials, as explained in the tutorial. + + +### Running the tests + +``` diff --git a/google-cloud/pom.xml b/google-cloud/pom.xml new file mode 100644 index 0000000000..0f1eff36f8 --- /dev/null +++ b/google-cloud/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + google-cloud + 0.1-SNAPSHOT + jar + google-cloud + Google Cloud Tutorials + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + + + + + com.google.cloud + google-cloud-storage + 1.16.0 + + + org.projectlombok + lombok + + ${lombok.version} + provided + + + + + 1.16.18 + 1.8 + UTF-8 + + + diff --git a/google-cloud/src/main/java/com/baeldung/google/cloud/storage/GoogleCloudStorage.java b/google-cloud/src/main/java/com/baeldung/google/cloud/storage/GoogleCloudStorage.java new file mode 100644 index 0000000000..a69171f1db --- /dev/null +++ b/google-cloud/src/main/java/com/baeldung/google/cloud/storage/GoogleCloudStorage.java @@ -0,0 +1,105 @@ +package com.baeldung.google.cloud.storage; + +import com.google.api.gax.paging.Page; +import com.google.auth.Credentials; +import com.google.auth.oauth2.GoogleCredentials; +import com.google.cloud.storage.*; +import lombok.extern.slf4j.Slf4j; + +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.WritableByteChannel; + +import static java.nio.charset.StandardCharsets.UTF_8; + +/** + * Simple class for creating, reading and modifying text blobs on Google Cloud + */ +@Slf4j +public class GoogleCloudStorage { + + private Storage storage; + private Bucket bucket; + + public static void main(String[] args) throws Exception { + + // Use this variation to read the Google authorization JSON from the resources directory with a path + // and a project name. + GoogleCloudStorage googleCloudStorage = + new GoogleCloudStorage("google-cloud/src/main/resources/google_auth.json", "baeldung-cloud-tutorial"); + + // Bucket require globally unique names, so you'll probably need to change this + Bucket bucket = googleCloudStorage.getBucket("baeldung-1-bucket"); + + // Save a simple string + BlobId blobId = googleCloudStorage.saveString("my-first-blob", "Hi there!", bucket); + + // Get it by blob id this time + String value = googleCloudStorage.getString(blobId); + + log.info("Read data: {}", value); + + googleCloudStorage.updateString(blobId, "Bye now!"); + + // Get the string by blob name + value = googleCloudStorage.getString("my-first-blob"); + + log.info("Read modified data: {}", value); + + + } + + + // Use path and project name + private GoogleCloudStorage(String pathToConfig, String projectId) throws IOException { + Credentials credentials = GoogleCredentials.fromStream(new FileInputStream(pathToConfig)); + storage = StorageOptions.newBuilder().setCredentials(credentials).setProjectId(projectId).build().getService(); + } + + // Check for bucket existence and create if needed. + private Bucket getBucket(String bucketName) { + bucket = storage.get(bucketName); + if (bucket == null) { + System.out.println("Creating new bucket."); + bucket = storage.create(BucketInfo.of(bucketName)); + } + return bucket; + } + + // Save a string to a blob + private BlobId saveString(String blobName, String value, Bucket bucket) { + byte[] bytes = value.getBytes(UTF_8); + Blob blob = bucket.create(blobName, bytes); + return blob.getBlobId(); + } + + + // get a blob by id + private String getString(BlobId blobId) { + Blob blob = storage.get(blobId); + return new String(blob.getContent()); + } + + + // get a blob by name + private String getString(String name) { + Page blobs = bucket.list(); + for (Blob blob: blobs.getValues()) { + if (name.equals(blob.getName())) { + return new String(blob.getContent()); + } + } + return "Blob not found"; + } + + // Update a blob + private void updateString(BlobId blobId, String newString) throws IOException { + Blob blob = storage.get(blobId); + if (blob != null) { + WritableByteChannel channel = blob.writer(); + channel.write(ByteBuffer.wrap(newString.getBytes(UTF_8))); + channel.close(); + } + } +} \ No newline at end of file diff --git a/guava/README.md b/guava/README.md index 7ab70cb01f..924187867e 100644 --- a/guava/README.md +++ b/guava/README.md @@ -19,6 +19,7 @@ - [Guide to Guava’s Ordering](http://www.baeldung.com/guava-ordering) - [Guide to Guava’s PreConditions](http://www.baeldung.com/guava-preconditions) - [Introduction to Guava CacheLoader](http://www.baeldung.com/guava-cacheloader) +- [Introduction to Guava Memoizer](http://www.baeldung.com/guava-memoizer) - [Guide to Guava’s EventBus](http://www.baeldung.com/guava-eventbus) - [Guide to Guava Multimap](http://www.baeldung.com/guava-multimap) - [Guide to Guava RangeSet](http://www.baeldung.com/guava-rangeset) diff --git a/guest/core-java/pom.xml b/guest/core-java/pom.xml index 222716386b..eda3846c1f 100644 --- a/guest/core-java/pom.xml +++ b/guest/core-java/pom.xml @@ -16,6 +16,24 @@ log4j-core ${log4j2.version} + + org.hamcrest + hamcrest-core + ${org.hamcrest.version} + test + + + org.hamcrest + hamcrest-library + ${org.hamcrest.version} + test + + + org.hamcrest + hamcrest-all + ${org.hamcrest.version} + test + @@ -32,5 +50,6 @@ 2.8.2 + 1.3 \ No newline at end of file diff --git a/guest/core-java/src/main/java/com/stackify/stream/Employee.java b/guest/core-java/src/main/java/com/stackify/stream/Employee.java new file mode 100644 index 0000000000..005990c863 --- /dev/null +++ b/guest/core-java/src/main/java/com/stackify/stream/Employee.java @@ -0,0 +1,46 @@ +package com.stackify.stream; + +public class Employee { + private Integer id; + private String name; + private Double salary; + + public Employee(Integer id, String name, Double salary) { + this.id = id; + this.name = name; + this.salary = salary; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Double getSalary() { + return salary; + } + + public void setSalary(Double salary) { + this.salary = salary; + } + + public void salaryIncrement(Double percentage) { + Double newSalary = salary + percentage * salary / 100; + setSalary(newSalary); + } + + public String toString() { + return "Id: " + id + " Name:" + name + " Price:" + salary; + } +} diff --git a/guest/core-java/src/main/java/com/stackify/stream/EmployeeRepository.java b/guest/core-java/src/main/java/com/stackify/stream/EmployeeRepository.java new file mode 100644 index 0000000000..223fee5e26 --- /dev/null +++ b/guest/core-java/src/main/java/com/stackify/stream/EmployeeRepository.java @@ -0,0 +1,21 @@ +package com.stackify.stream; + +import java.util.List; + +public class EmployeeRepository { + private List empList; + + public EmployeeRepository(List empList) { + this.empList = empList; + + } + public Employee findById(Integer id) { + for (Employee emp : empList) { + if (emp.getId() == id) { + return emp; + } + } + + return null; + } +} diff --git a/guest/core-java/src/test/java/com/stackify/stream/EmployeeTest.java b/guest/core-java/src/test/java/com/stackify/stream/EmployeeTest.java new file mode 100644 index 0000000000..cf988d035a --- /dev/null +++ b/guest/core-java/src/test/java/com/stackify/stream/EmployeeTest.java @@ -0,0 +1,455 @@ +package com.stackify.stream; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.beans.HasPropertyWithValue.hasProperty; +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.DoubleSummaryStatistics; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.Set; +import java.util.Vector; +import java.util.function.BinaryOperator; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.junit.After; +import org.junit.Test; + +public class EmployeeTest { + private String fileName = "src/test/resources/test.txt"; + + private static Employee[] arrayOfEmps = { + new Employee(1, "Jeff Bezos", 100000.0), + new Employee(2, "Bill Gates", 200000.0), + new Employee(3, "Mark Zuckerberg", 300000.0) + }; + + private static List empList = Arrays.asList(arrayOfEmps); + private static EmployeeRepository employeeRepository = new EmployeeRepository(empList); + + @After + public void cleanup() throws IOException { + Files.deleteIfExists(Paths.get(fileName)); + } + + @Test + public void whenGetStreamFromList_ObtainStream() { + assert(empList.stream() instanceof Stream); + } + + @Test + public void whenGetStreamFromArray_ObtainStream() { + assert(Stream.of(arrayOfEmps) instanceof Stream); + } + + @Test + public void whenGetStreamFromElements_ObtainStream() { + assert(Stream.of(arrayOfEmps[0], arrayOfEmps[1], arrayOfEmps[2]) instanceof Stream); + } + + @Test + public void whenBuildStreamFromElements_ObtainStream() { + Stream.Builder empStreamBuilder = Stream.builder(); + + empStreamBuilder.accept(arrayOfEmps[0]); + empStreamBuilder.accept(arrayOfEmps[1]); + empStreamBuilder.accept(arrayOfEmps[2]); + + Stream empStream = empStreamBuilder.build(); + + assert(empStream instanceof Stream); + } + + @Test + public void whenIncrementSalaryForEachEmployee_thenApplyNewSalary() { + Employee[] arrayOfEmps = { + new Employee(1, "Jeff Bezos", 100000.0), + new Employee(2, "Bill Gates", 200000.0), + new Employee(3, "Mark Zuckerberg", 300000.0) + }; + + List empList = Arrays.asList(arrayOfEmps); + + empList.stream().forEach(e -> e.salaryIncrement(10.0)); + + assertThat(empList, contains( + hasProperty("salary", equalTo(110000.0)), + hasProperty("salary", equalTo(220000.0)), + hasProperty("salary", equalTo(330000.0)) + )); + } + + @Test + public void whenIncrementSalaryUsingPeek_thenApplyNewSalary() { + Employee[] arrayOfEmps = { + new Employee(1, "Jeff Bezos", 100000.0), + new Employee(2, "Bill Gates", 200000.0), + new Employee(3, "Mark Zuckerberg", 300000.0) + }; + + List empList = Arrays.asList(arrayOfEmps); + + empList.stream() + .peek(e -> e.salaryIncrement(10.0)) + .peek(System.out::println) + .collect(Collectors.toList()); + + assertThat(empList, contains( + hasProperty("salary", equalTo(110000.0)), + hasProperty("salary", equalTo(220000.0)), + hasProperty("salary", equalTo(330000.0)) + )); + } + + @Test + public void whenMapIdToEmployees_thenGetEmployeeStream() { + Integer[] empIds = { 1, 2, 3 }; + + List employees = Stream.of(empIds) + .map(employeeRepository::findById) + .collect(Collectors.toList()); + + assertEquals(employees.size(), empIds.length); + } + + @Test + public void whenFlatMapEmployeeNames_thenGetNameStream() { + List> namesNested = Arrays.asList( + Arrays.asList("Jeff", "Bezos"), + Arrays.asList("Bill", "Gates"), + Arrays.asList("Mark", "Zuckerberg")); + + List namesFlatStream = namesNested.stream() + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + assertEquals(namesFlatStream.size(), namesNested.size() * 2); + } + + @Test + public void whenFilterEmployees_thenGetFilteredStream() { + Integer[] empIds = { 1, 2, 3, 4 }; + + List employees = Stream.of(empIds) + .map(employeeRepository::findById) + .filter(e -> e != null) + .filter(e -> e.getSalary() > 200000) + .collect(Collectors.toList()); + + assertEquals(Arrays.asList(arrayOfEmps[2]), employees); + } + + @Test + public void whenFindFirst_thenGetFirstEmployeeInStream() { + Integer[] empIds = { 1, 2, 3, 4 }; + + Employee employee = Stream.of(empIds) + .map(employeeRepository::findById) + .filter(e -> e != null) + .filter(e -> e.getSalary() > 100000) + .findFirst() + .orElse(null); + + assertEquals(employee.getSalary(), new Double(200000)); + } + + @Test + public void whenCollectStreamToList_thenGetList() { + List employees = empList.stream().collect(Collectors.toList()); + + assertEquals(empList, employees); + } + + @Test + public void whenStreamToArray_thenGetArray() { + Employee[] employees = empList.stream().toArray(Employee[]::new); + + assertThat(empList.toArray(), equalTo(employees)); + } + + @Test + public void whenStreamCount_thenGetElementCount() { + Long empCount = empList.stream() + .filter(e -> e.getSalary() > 200000) + .count(); + + assertEquals(empCount, new Long(1)); + } + + @Test + public void whenLimitInfiniteStream_thenGetFiniteElements() { + Stream infiniteStream = Stream.iterate(2, i -> i * 2); + + List collect = infiniteStream + .skip(3) + .limit(5) + .collect(Collectors.toList()); + + assertEquals(collect, Arrays.asList(16, 32, 64, 128, 256)); + } + + @Test + public void whenSortStream_thenGetSortedStream() { + List employees = empList.stream() + .sorted((e1, e2) -> e1.getName().compareTo(e2.getName())) + .collect(Collectors.toList()); + + assertEquals(employees.get(0).getName(), "Bill Gates"); + assertEquals(employees.get(1).getName(), "Jeff Bezos"); + assertEquals(employees.get(2).getName(), "Mark Zuckerberg"); + } + + + @Test + public void whenFindMin_thenGetMinElementFromStream() { + Employee firstEmp = empList.stream() + .min((e1, e2) -> e1.getId() - e2.getId()) + .orElseThrow(NoSuchElementException::new); + + assertEquals(firstEmp.getId(), new Integer(1)); + } + + @Test + public void whenFindMax_thenGetMaxElementFromStream() { + Employee maxSalEmp = empList.stream() + .max(Comparator.comparing(Employee::getSalary)) + .orElseThrow(NoSuchElementException::new); + + assertEquals(maxSalEmp.getSalary(), new Double(300000.0)); + } + + @Test + public void whenApplyDistinct_thenRemoveDuplicatesFromStream() { + List intList = Arrays.asList(2, 5, 3, 2, 4, 3); + List distinctIntList = intList.stream().distinct().collect(Collectors.toList()); + + assertEquals(distinctIntList, Arrays.asList(2, 5, 3, 4)); + } + + @Test + public void whenApplyMatch_thenReturnBoolean() { + List intList = Arrays.asList(2, 4, 5, 6, 8); + + boolean allEven = intList.stream().allMatch(i -> i % 2 == 0); + boolean oneEven = intList.stream().anyMatch(i -> i % 2 == 0); + boolean noneMultipleOfThree = intList.stream().noneMatch(i -> i % 3 == 0); + + assertEquals(allEven, false); + assertEquals(oneEven, true); + assertEquals(noneMultipleOfThree, false); + } + + @Test + public void whenFindMaxOnIntStream_thenGetMaxInteger() { + Integer latestEmpId = empList.stream() + .mapToInt(Employee::getId) + .max() + .orElseThrow(NoSuchElementException::new); + + assertEquals(latestEmpId, new Integer(3)); + } + + @Test + public void whenApplySumOnIntStream_thenGetSum() { + Double avgSal = empList.stream() + .mapToDouble(Employee::getSalary) + .average() + .orElseThrow(NoSuchElementException::new); + + assertEquals(avgSal, new Double(200000)); + } + + @Test + public void whenApplyReduceOnStream_thenGetValue() { + Double sumSal = empList.stream() + .map(Employee::getSalary) + .reduce(0.0, Double::sum); + + assertEquals(sumSal, new Double(600000)); + } + + @Test + public void whenCollectByJoining_thenGetJoinedString() { + String empNames = empList.stream() + .map(Employee::getName) + .collect(Collectors.joining(", ")) + .toString(); + + assertEquals(empNames, "Jeff Bezos, Bill Gates, Mark Zuckerberg"); + } + + @Test + public void whenCollectBySet_thenGetSet() { + Set empNames = empList.stream() + .map(Employee::getName) + .collect(Collectors.toSet()); + + assertEquals(empNames.size(), 3); + } + + @Test + public void whenToVectorCollection_thenGetVector() { + Vector empNames = empList.stream() + .map(Employee::getName) + .collect(Collectors.toCollection(Vector::new)); + + assertEquals(empNames.size(), 3); + } + + @Test + public void whenApplySummarizing_thenGetBasicStats() { + DoubleSummaryStatistics stats = empList.stream() + .collect(Collectors.summarizingDouble(Employee::getSalary)); + + assertEquals(stats.getCount(), 3); + assertEquals(stats.getSum(), 600000.0, 0); + assertEquals(stats.getMin(), 100000.0, 0); + assertEquals(stats.getMax(), 300000.0, 0); + assertEquals(stats.getAverage(), 200000.0, 0); + } + + @Test + public void whenApplySummaryStatistics_thenGetBasicStats() { + DoubleSummaryStatistics stats = empList.stream() + .mapToDouble(Employee::getSalary) + .summaryStatistics(); + + assertEquals(stats.getCount(), 3); + assertEquals(stats.getSum(), 600000.0, 0); + assertEquals(stats.getMin(), 100000.0, 0); + assertEquals(stats.getMax(), 300000.0, 0); + assertEquals(stats.getAverage(), 200000.0, 0); + } + + @Test + public void whenStreamPartition_thenGetMap() { + List intList = Arrays.asList(2, 4, 5, 6, 8); + Map> isEven = intList.stream().collect( + Collectors.partitioningBy(i -> i % 2 == 0)); + + assertEquals(isEven.get(true).size(), 4); + assertEquals(isEven.get(false).size(), 1); + } + + @Test + public void whenStreamGroupingBy_thenGetMap() { + Map> groupByAlphabet = empList.stream().collect( + Collectors.groupingBy(e -> new Character(e.getName().charAt(0)))); + + assertEquals(groupByAlphabet.get('B').get(0).getName(), "Bill Gates"); + assertEquals(groupByAlphabet.get('J').get(0).getName(), "Jeff Bezos"); + assertEquals(groupByAlphabet.get('M').get(0).getName(), "Mark Zuckerberg"); + } + + @Test + public void whenStreamMapping_thenGetMap() { + Map> idGroupedByAlphabet = empList.stream().collect( + Collectors.groupingBy(e -> new Character(e.getName().charAt(0)), + Collectors.mapping(Employee::getId, Collectors.toList()))); + + assertEquals(idGroupedByAlphabet.get('B').get(0), new Integer(2)); + assertEquals(idGroupedByAlphabet.get('J').get(0), new Integer(1)); + assertEquals(idGroupedByAlphabet.get('M').get(0), new Integer(3)); + } + + @Test + public void whenStreamReducing_thenGetValue() { + Double percentage = 10.0; + Double salIncrOverhead = empList.stream().collect(Collectors.reducing( + 0.0, e -> e.getSalary() * percentage / 100, (s1, s2) -> s1 + s2)); + + assertEquals(salIncrOverhead, 60000.0, 0); + } + + @Test + public void whenStreamGroupingAndReducing_thenGetMap() { + Comparator byNameLength = Comparator.comparing(Employee::getName); + + Map> longestNameByAlphabet = empList.stream().collect( + Collectors.groupingBy(e -> new Character(e.getName().charAt(0)), + Collectors.reducing(BinaryOperator.maxBy(byNameLength)))); + + assertEquals(longestNameByAlphabet.get('B').get().getName(), "Bill Gates"); + assertEquals(longestNameByAlphabet.get('J').get().getName(), "Jeff Bezos"); + assertEquals(longestNameByAlphabet.get('M').get().getName(), "Mark Zuckerberg"); + } + + @Test + public void whenParallelStream_thenPerformOperationsInParallel() { + Employee[] arrayOfEmps = { + new Employee(1, "Jeff Bezos", 100000.0), + new Employee(2, "Bill Gates", 200000.0), + new Employee(3, "Mark Zuckerberg", 300000.0) + }; + + List empList = Arrays.asList(arrayOfEmps); + + empList.stream().parallel().forEach(e -> e.salaryIncrement(10.0)); + + assertThat(empList, contains( + hasProperty("salary", equalTo(110000.0)), + hasProperty("salary", equalTo(220000.0)), + hasProperty("salary", equalTo(330000.0)) + )); + } + + @Test + public void whenGenerateStream_thenGetInfiniteStream() { + Stream.generate(Math::random) + .limit(5) + .forEach(System.out::println); + } + + @Test + public void whenIterateStream_thenGetInfiniteStream() { + Stream evenNumStream = Stream.iterate(2, i -> i * 2); + + List collect = evenNumStream + .limit(5) + .collect(Collectors.toList()); + + assertEquals(collect, Arrays.asList(2, 4, 8, 16, 32)); + } + + @Test + public void whenStreamToFile_thenGetFile() throws IOException { + String[] words = { + "hello", + "refer", + "world", + "level" + }; + + try (PrintWriter pw = new PrintWriter( + Files.newBufferedWriter(Paths.get(fileName)))) { + Stream.of(words).forEach(pw::println); + } + } + + private List getPalindrome(Stream stream, int length) { + return stream.filter(s -> s.length() == length) + .filter(s -> s.compareToIgnoreCase( + new StringBuilder(s).reverse().toString()) == 0) + .collect(Collectors.toList()); + } + + @Test + public void whenFileToStream_thenGetStream() throws IOException { + whenStreamToFile_thenGetFile(); + + List str = getPalindrome(Files.lines(Paths.get(fileName)), 5); + assertThat(str, contains("refer", "level")); + } +} diff --git a/guest/core-java/src/test/resources/.keep b/guest/core-java/src/test/resources/.keep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java b/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java index c8b3397b09..506e674984 100644 --- a/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java +++ b/hibernate5/src/main/java/com/baeldung/hibernate/converters/PersonNameConverter.java @@ -11,31 +11,49 @@ public class PersonNameConverter implements AttributeConverter= 2 && pieces[1] != null && !pieces[1].isEmpty()) { + personName.setName(pieces[1]); + } + } else { + personName.setName(firstPiece); + } return personName; } diff --git a/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java index aec2311294..204d8775ff 100644 --- a/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java +++ b/hibernate5/src/test/java/com/baeldung/hibernate/converter/PersonNameConverterTest.java @@ -71,4 +71,130 @@ public class PersonNameConverterTest { .getSurname(), surname); } + @Test + public void givenPersonNameNull_WhenSaving_ThenNullStored() { + final String name = null; + final String surname = null; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals("", dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName(), null); + } + + @Test + public void givenPersonNameWithoutName_WhenSaving_ThenNotNameStored() { + final String name = null; + final String surname = "surname"; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals("surname, ", dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName() + .getName(), name); + assertEquals(dbPerson.getPersonName() + .getSurname(), surname); + } + + @Test + public void givenPersonNameWithoutSurName_WhenSaving_ThenNotSurNameStored() { + final String name = "name"; + final String surname = null; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals("name", dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName() + .getName(), name); + assertEquals(dbPerson.getPersonName() + .getSurname(), surname); + } + + @Test + public void givenPersonNameEmptyFields_WhenSaving_ThenFielsNotStored() { + final String name = ""; + final String surname = ""; + + PersonName personName = new PersonName(); + personName.setName(name); + personName.setSurname(surname); + + Person person = new Person(); + person.setPersonName(personName); + + Long id = (Long) session.save(person); + + session.flush(); + session.clear(); + + String dbPersonName = (String) session.createNativeQuery("select p.personName from PersonTable p where p.id = :id") + .setParameter("id", id) + .getSingleResult(); + + assertEquals("", dbPersonName); + + Person dbPerson = session.createNativeQuery("select * from PersonTable p where p.id = :id", Person.class) + .setParameter("id", id) + .getSingleResult(); + + assertEquals(dbPerson.getPersonName(), null); + } + } diff --git a/java-lite/pom.xml b/java-lite/pom.xml index eb18bc40a5..d7950487ca 100644 --- a/java-lite/pom.xml +++ b/java-lite/pom.xml @@ -1,7 +1,6 @@ - + 4.0.0 org.baeldung @@ -22,10 +21,15 @@ 5.1.45 1.7.0 1.8.2 - 4.11 + 4.12 + + + src/main/webapp/WEB-INF + + org.eclipse.jetty @@ -85,7 +89,14 @@ system ${java.home}/../lib/tools.jar - + + + org.javalite + activeweb-testing + 1.15 + test + + junit junit diff --git a/java-lite/src/main/java/app/config/AppBootstrap.java b/java-lite/src/main/java/app/config/AppBootstrap.java index 7a87c2d0a7..02c8360986 100644 --- a/java-lite/src/main/java/app/config/AppBootstrap.java +++ b/java-lite/src/main/java/app/config/AppBootstrap.java @@ -3,7 +3,15 @@ package app.config; import org.javalite.activeweb.AppContext; import org.javalite.activeweb.Bootstrap; +import com.google.inject.Guice; +import com.google.inject.Injector; + +import app.services.ArticleServiceModule; + public class AppBootstrap extends Bootstrap { public void init(AppContext context) { } + public Injector getInjector() { + return Guice.createInjector(new ArticleServiceModule()); + } } diff --git a/java-lite/src/main/java/app/controllers/ArticleController.java b/java-lite/src/main/java/app/controllers/ArticleController.java new file mode 100755 index 0000000000..2b8dc452bd --- /dev/null +++ b/java-lite/src/main/java/app/controllers/ArticleController.java @@ -0,0 +1,28 @@ +package app.controllers; + +import javax.inject.Inject; + +import org.javalite.activeweb.AppController; + +import app.services.ArticleService; + +public class ArticleController extends AppController { + + @Inject + private ArticleService articleService; + + public void index() { + view("articles", articleService.getArticles()); + } + + public void search() { + + String keyword = param("key"); + if (null != keyword) { + assign("article", articleService.search(keyword)); + } else { + render("/common/error"); + } + + } +} diff --git a/java-lite/src/main/java/app/controllers/HomeController.java b/java-lite/src/main/java/app/controllers/HomeController.java new file mode 100755 index 0000000000..0e284af0ad --- /dev/null +++ b/java-lite/src/main/java/app/controllers/HomeController.java @@ -0,0 +1,11 @@ +package app.controllers; + +import org.javalite.activeweb.AppController; + +public class HomeController extends AppController { + + public void index() { + render("index"); + } + +} diff --git a/java-lite/src/main/java/app/models/Article.java b/java-lite/src/main/java/app/models/Article.java new file mode 100755 index 0000000000..db318f4468 --- /dev/null +++ b/java-lite/src/main/java/app/models/Article.java @@ -0,0 +1,50 @@ +package app.models; + +public class Article { + + private String title; + private String author; + private String words; + private String date; + + public Article(String title, String author, String words, String date) { + super(); + this.title = title; + this.author = author; + this.words = words; + this.date = date; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getWords() { + return words; + } + + public void setWords(String words) { + this.words = words; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + +} \ No newline at end of file diff --git a/java-lite/src/main/java/app/services/ArticleService.java b/java-lite/src/main/java/app/services/ArticleService.java new file mode 100755 index 0000000000..ddd0b3ed10 --- /dev/null +++ b/java-lite/src/main/java/app/services/ArticleService.java @@ -0,0 +1,13 @@ +package app.services; + +import java.util.List; + +import app.models.Article; + +public interface ArticleService { + + List
getArticles(); + + Article search(String keyword); + +} diff --git a/java-lite/src/main/java/app/services/ArticleServiceImpl.java b/java-lite/src/main/java/app/services/ArticleServiceImpl.java new file mode 100755 index 0000000000..fc81576f91 --- /dev/null +++ b/java-lite/src/main/java/app/services/ArticleServiceImpl.java @@ -0,0 +1,34 @@ +package app.services; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +import app.models.Article; + +public class ArticleServiceImpl implements ArticleService { + + public List
getArticles() { + return fetchArticles(); + } + + public Article search(String keyword) { + Article ar = new Article("Article with " + keyword, "baeldung", "1250", Instant.now() + .toString()); + return ar; + } + + private List
fetchArticles() { + Article ar1 = new Article("Introduction to ActiveWeb", "baeldung", "1650", Instant.now() + .toString()); + + Article ar = new Article("Introduction to Mule", "baeldung", "1650", Instant.now() + .toString()); + List
articles = new ArrayList
(); + articles.add(ar); + articles.add(ar1); + return articles; + + } + +} diff --git a/java-lite/src/main/java/app/services/ArticleServiceModule.java b/java-lite/src/main/java/app/services/ArticleServiceModule.java new file mode 100755 index 0000000000..feae2a2ff7 --- /dev/null +++ b/java-lite/src/main/java/app/services/ArticleServiceModule.java @@ -0,0 +1,12 @@ +package app.services; + +import com.google.inject.AbstractModule; + +public class ArticleServiceModule extends AbstractModule { + + @Override + protected void configure() { + bind(ArticleService.class).to(ArticleServiceImpl.class) + .asEagerSingleton(); + } +} diff --git a/java-lite/src/main/webapp/WEB-INF/views/article/index.ftl b/java-lite/src/main/webapp/WEB-INF/views/article/index.ftl new file mode 100755 index 0000000000..2d5f211427 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/article/index.ftl @@ -0,0 +1,18 @@ +<@content for="title">Articles + + + + + + + + +<#list articles as article> + + + + + + + +
TitleAuthorWords #Date Published
${article.title}${article.author}${article.words}${article.date}
\ No newline at end of file diff --git a/java-lite/src/main/webapp/WEB-INF/views/article/search.ftl b/java-lite/src/main/webapp/WEB-INF/views/article/search.ftl new file mode 100755 index 0000000000..45a73808ed --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/article/search.ftl @@ -0,0 +1,17 @@ +<@content for="title">Search + + + + + + + + + + + + + + + +
TitleAuthorWords #Date Published
${article.title}${article.author}${article.words}${article.date}
\ No newline at end of file diff --git a/java-lite/src/main/webapp/WEB-INF/views/common/error.ftl b/java-lite/src/main/webapp/WEB-INF/views/common/error.ftl new file mode 100755 index 0000000000..5fbf3c5243 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/common/error.ftl @@ -0,0 +1,3 @@ +<@content for="title">Simple Web App + +

Application error

diff --git a/java-lite/src/main/webapp/WEB-INF/views/home/index.ftl b/java-lite/src/main/webapp/WEB-INF/views/home/index.ftl new file mode 100755 index 0000000000..ae6a7c56a5 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/home/index.ftl @@ -0,0 +1,3 @@ +<@content for="title">Simple Web App + +

Baeldung ActiveWeb Demo Application

diff --git a/java-lite/src/main/webapp/WEB-INF/views/layouts/default_layout.ftl b/java-lite/src/main/webapp/WEB-INF/views/layouts/default_layout.ftl new file mode 100755 index 0000000000..2985e56278 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/layouts/default_layout.ftl @@ -0,0 +1,16 @@ +<#setting url_escaping_charset='ISO-8859-1'> + + + + + + +
+<#include "header.ftl" > +
+ ${page_content} +
+<#include "footer.ftl" > +
+ + diff --git a/java-lite/src/main/webapp/WEB-INF/views/layouts/footer.ftl b/java-lite/src/main/webapp/WEB-INF/views/layouts/footer.ftl new file mode 100755 index 0000000000..1408547424 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/layouts/footer.ftl @@ -0,0 +1,3 @@ + diff --git a/java-lite/src/main/webapp/WEB-INF/views/layouts/header.ftl b/java-lite/src/main/webapp/WEB-INF/views/layouts/header.ftl new file mode 100755 index 0000000000..8187435035 --- /dev/null +++ b/java-lite/src/main/webapp/WEB-INF/views/layouts/header.ftl @@ -0,0 +1,4 @@ + + diff --git a/java-lite/src/main/webapp/WEB-INF/web.xml b/java-lite/src/main/webapp/WEB-INF/web.xml index c285876c86..23bb8b865e 100644 --- a/java-lite/src/main/webapp/WEB-INF/web.xml +++ b/java-lite/src/main/webapp/WEB-INF/web.xml @@ -6,6 +6,10 @@ dispatcher org.javalite.activeweb.RequestDispatcher + + root_controller + home + exclusions css,images,js,ico diff --git a/java-lite/src/test/java/app/controllers/ArticleControllerSpec.java b/java-lite/src/test/java/app/controllers/ArticleControllerSpec.java new file mode 100755 index 0000000000..882441dad3 --- /dev/null +++ b/java-lite/src/test/java/app/controllers/ArticleControllerSpec.java @@ -0,0 +1,31 @@ +package app.controllers; + +import org.javalite.activeweb.ControllerSpec; +import org.junit.Before; +import org.junit.Test; + +import com.google.inject.Guice; + +import app.services.ArticleServiceModule; + +public class ArticleControllerSpec extends ControllerSpec { + + @Before + public void before() { + setInjector(Guice.createInjector(new ArticleServiceModule())); + } + + @Test + public void whenReturnedArticlesThenCorrect() { + request().get("index"); + a(responseContent()).shouldContain("Introduction to Mule"); + } + + @Test + public void givenKeywordWhenFoundArticleThenCorrect() { + request().param("key", "Java") + .get("search"); + a(responseContent()).shouldContain("Article with Java"); + } + +} diff --git a/microprofile/pom.xml b/microprofile/pom.xml new file mode 100644 index 0000000000..ce8a2d13ca --- /dev/null +++ b/microprofile/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + + com.baeldung + microprofile + 1.0-SNAPSHOT + war + + + UTF-8 + UTF-8 + 1.8 + 1.8 + library + ${project.build.directory}/${app.name}-service.jar + runnable + + + + + org.eclipse.microprofile + microprofile + 1.2 + provided + pom + + + + + + + maven-war-plugin + + false + pom.xml + + + + net.wasdev.wlp.maven.plugins + liberty-maven-plugin + 2.1.2 + + + io.openliberty + openliberty-runtime + 17.0.0.4 + zip + + ${basedir}/src/main/liberty/config/server.xml + ${package.file} + ${packaging.type} + false + project + + / + ${project.artifactId}-${project.version}.war + 9080 + 9443 + + + + + install-server + prepare-package + + install-server + create-server + install-feature + + + + package-server-with-apps + package + + install-apps + package-server + + + + + + + + diff --git a/microprofile/src/main/java/com/baeldung/microprofile/LibraryApplication.java b/microprofile/src/main/java/com/baeldung/microprofile/LibraryApplication.java new file mode 100644 index 0000000000..f5eccf969e --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/LibraryApplication.java @@ -0,0 +1,8 @@ +package com.baeldung.microprofile; + +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.core.Application; + +@ApplicationPath("/library") +public class LibraryApplication extends Application { +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/model/Book.java b/microprofile/src/main/java/com/baeldung/microprofile/model/Book.java new file mode 100644 index 0000000000..44b7f5428d --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/model/Book.java @@ -0,0 +1,50 @@ +package com.baeldung.microprofile.model; + +public class Book { + + private String id; + private String isbn; + private String name; + private String author; + private Integer pages; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public Integer getPages() { + return pages; + } + + public void setPages(Integer pages) { + this.pages = pages; + } +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java new file mode 100644 index 0000000000..f7d0bfc5f7 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookListMessageBodyWriter.java @@ -0,0 +1,42 @@ +package com.baeldung.microprofile.providers; + +import com.baeldung.microprofile.model.Book; +import com.baeldung.microprofile.util.BookMapper; + +import javax.json.Json; +import javax.json.JsonArray; +import javax.json.JsonWriter; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.util.List; + +@Provider +@Produces(MediaType.APPLICATION_JSON) +public class BookListMessageBodyWriter implements MessageBodyWriter> { + + @Override + public boolean isWriteable(Class clazz, Type genericType, Annotation[] annotations, MediaType mediaType) { + return true; + } + + @Override + public long getSize(List books, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return 0; + } + + @Override + public void writeTo(List books, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { + JsonWriter jsonWriter = Json.createWriter(entityStream); + JsonArray jsonArray = BookMapper.map(books); + jsonWriter.writeArray(jsonArray); + jsonWriter.close(); + } +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java new file mode 100644 index 0000000000..26ce4c1b64 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyReader.java @@ -0,0 +1,30 @@ +package com.baeldung.microprofile.providers; + +import com.baeldung.microprofile.model.Book; +import com.baeldung.microprofile.util.BookMapper; + +import javax.ws.rs.Consumes; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +@Provider +@Consumes(MediaType.APPLICATION_JSON) +public class BookMessageBodyReader implements MessageBodyReader { + + @Override + public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type.equals(Book.class); + } + + @Override + public Book readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException { + return BookMapper.map(entityStream); + } +} \ No newline at end of file diff --git a/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java new file mode 100644 index 0000000000..9bc6e89958 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/providers/BookMessageBodyWriter.java @@ -0,0 +1,57 @@ +package com.baeldung.microprofile.providers; + +import com.baeldung.microprofile.model.Book; +import com.baeldung.microprofile.util.BookMapper; + +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonWriter; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.Provider; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +@Provider +@Produces(MediaType.APPLICATION_JSON) +public class BookMessageBodyWriter implements MessageBodyWriter { + @Override + public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return type.equals(Book.class); + } + + /* + Deprecated in JAX RS 2.0 + */ + @Override + public long getSize(Book book, Class type, Type genericType, Annotation[] annotations, MediaType mediaType) { + return 0; + } + + /** + * Marsahl Book to OutputStream + * + * @param book + * @param type + * @param genericType + * @param annotations + * @param mediaType + * @param httpHeaders + * @param entityStream + * @throws IOException + * @throws WebApplicationException + */ + @Override + public void writeTo(Book book, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException { + JsonWriter jsonWriter = Json.createWriter(entityStream); + JsonObject jsonObject = BookMapper.map(book); + jsonWriter.writeObject(jsonObject); + jsonWriter.close(); + } + +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/repo/BookManager.java b/microprofile/src/main/java/com/baeldung/microprofile/repo/BookManager.java new file mode 100644 index 0000000000..924cf0ce71 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/repo/BookManager.java @@ -0,0 +1,53 @@ +package com.baeldung.microprofile.repo; + +import com.baeldung.microprofile.model.Book; + +import javax.enterprise.context.ApplicationScoped; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +@ApplicationScoped +public class BookManager { + + private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMM"); + private AtomicInteger bookIdGenerator = new AtomicInteger(0); + + private ConcurrentMap inMemoryStore = new ConcurrentHashMap<>(); + + public BookManager() { + Book book = new Book(); + book.setId(getNextId()); + book.setName("Building Microservice With Eclipse MicroProfile"); + book.setIsbn("1"); + book.setAuthor("baeldung"); + book.setPages(420); + inMemoryStore.put(book.getId(), book); + } + + private String getNextId() { + String date = LocalDate.now().format(formatter); + return String.format("%04d-%s", bookIdGenerator.incrementAndGet(), date); + } + + public String add(Book book) { + String id = getNextId(); + book.setId(id); + inMemoryStore.put(id, book); + return id; + } + + public Book get(String id) { + return inMemoryStore.get(id); + } + + public List getAll() { + List books = new ArrayList<>(); + books.addAll(inMemoryStore.values()); + return books; + } +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/util/BookMapper.java b/microprofile/src/main/java/com/baeldung/microprofile/util/BookMapper.java new file mode 100644 index 0000000000..861b172299 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/util/BookMapper.java @@ -0,0 +1,72 @@ +package com.baeldung.microprofile.util; + +import com.baeldung.microprofile.model.Book; + +import javax.json.*; +import java.io.InputStream; +import java.util.List; + +public class BookMapper { + + public static JsonObject map(Book book) { + JsonObjectBuilder builder = Json.createObjectBuilder(); + addValue(builder, "id", book.getId()); + addValue(builder, "isbn", book.getIsbn()); + addValue(builder, "name", book.getName()); + addValue(builder, "author", book.getAuthor()); + addValue(builder, "pages", book.getPages()); + return builder.build(); + } + + private static void addValue(JsonObjectBuilder builder, String key, Object value) { + if (value != null) { + builder.add(key, value.toString()); + } else { + builder.addNull(key); + } + } + + public static JsonArray map(List books) { + final JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); + books.forEach(book -> { + JsonObject jsonObject = map(book); + arrayBuilder.add(jsonObject); + }); + return arrayBuilder.build(); + } + + public static Book map(InputStream is) { + try(JsonReader jsonReader = Json.createReader(is)) { + JsonObject jsonObject = jsonReader.readObject(); + Book book = new Book(); + book.setId(getStringFromJson("id", jsonObject)); + book.setIsbn(getStringFromJson("isbn", jsonObject)); + book.setName(getStringFromJson("name", jsonObject)); + book.setAuthor(getStringFromJson("author", jsonObject)); + book.setPages(getIntFromJson("pages",jsonObject)); + return book; + } + } + + private static String getStringFromJson(String key, JsonObject json) { + String returnedString = null; + if (json.containsKey(key)) { + JsonString value = json.getJsonString(key); + if (value != null) { + returnedString = value.getString(); + } + } + return returnedString; + } + + private static Integer getIntFromJson(String key, JsonObject json) { + Integer returnedValue = null; + if (json.containsKey(key)) { + JsonNumber value = json.getJsonNumber(key); + if (value != null) { + returnedValue = value.intValue(); + } + } + return returnedValue; + } +} diff --git a/microprofile/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java b/microprofile/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java new file mode 100644 index 0000000000..13143a5644 --- /dev/null +++ b/microprofile/src/main/java/com/baeldung/microprofile/web/BookEndpoint.java @@ -0,0 +1,42 @@ +package com.baeldung.microprofile.web; + +import com.baeldung.microprofile.model.Book; +import com.baeldung.microprofile.repo.BookManager; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.ws.rs.*; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; + +@Path("books") +@RequestScoped +public class BookEndpoint { + + @Inject + private BookManager bookManager; + + @GET + @Path("{id}") + @Produces(MediaType.APPLICATION_JSON) + public Response getBook(@PathParam("id") String id) { + Book book = bookManager.get(id); + return Response.ok(book).build(); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Response getAllBooks() { + return Response.ok(bookManager.getAll()).build(); + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + public Response add(Book book) { + String bookId = bookManager.add(book); + return Response.created( + UriBuilder.fromResource(this.getClass()).path(bookId).build()) + .build(); + } +} diff --git a/microprofile/src/main/liberty/config/server.xml b/microprofile/src/main/liberty/config/server.xml new file mode 100644 index 0000000000..2b855bee05 --- /dev/null +++ b/microprofile/src/main/liberty/config/server.xml @@ -0,0 +1,11 @@ + + + jaxrs-2.0 + cdi-1.2 + jsonp-1.0 + + + + + diff --git a/pom.xml b/pom.xml index 271fb847d3..ef89e85eb3 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ parent-boot-5 - asm + asm atomix apache-cayenne aws @@ -48,9 +48,9 @@ core-java core-java-io core-java-8 - + couchbase deltaspike @@ -66,6 +66,7 @@ geotools testing-modules/groovy-spock + google-cloud gson guava guava-modules/guava-18 @@ -89,7 +90,7 @@ vavr java-lite - java-rmi + java-rmi java-vavr-stream javax-servlets javaxval @@ -108,7 +109,7 @@ libraries libraries-data - linkrest + linkrest logging-modules/log-mdc logging-modules/log4j logging-modules/log4j2 @@ -249,9 +250,9 @@ spring-reactor spring-vertx spring-jinq - + spring-rest-embedded-tomcat - + testing-modules/testing testing-modules/testng @@ -278,7 +279,7 @@ saas deeplearning4j lucene - vraptor + vraptor persistence-modules/java-cockroachdb jersey diff --git a/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java index 9d5d094875..81dfda3bb3 100644 --- a/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java +++ b/reactor-core/src/test/java/com/baeldung/reactor/core/CombiningPublishersTest.java @@ -17,7 +17,7 @@ public class CombiningPublishersTest { @Test - public void testMerge() { + public void givenFluxes_whenMergeIsInvoked_thenMerge() { Flux fluxOfIntegers = Flux.merge( evenNumbers, oddNumbers); @@ -33,7 +33,7 @@ public class CombiningPublishersTest { } @Test - public void testMergeWithDelayedElements() { + public void givenFluxes_whenMergeWithDelayedElementsIsInvoked_thenMergeWithDelayedElements() { Flux fluxOfIntegers = Flux.merge( evenNumbers.delayElements(Duration.ofMillis(500L)), oddNumbers.delayElements(Duration.ofMillis(300L))); @@ -49,7 +49,7 @@ public class CombiningPublishersTest { } @Test - public void testConcat() { + public void givenFluxes_whenConcatIsInvoked_thenConcat() { Flux fluxOfIntegers = Flux.concat( evenNumbers.delayElements(Duration.ofMillis(500L)), oddNumbers.delayElements(Duration.ofMillis(300L))); @@ -65,7 +65,7 @@ public class CombiningPublishersTest { } @Test - public void testConcatWith() { + public void givenFluxes_whenConcatWithIsInvoked_thenConcatWith() { Flux fluxOfIntegers = evenNumbers .concatWith(oddNumbers); @@ -80,7 +80,7 @@ public class CombiningPublishersTest { } @Test - public void testCombineLatest() { + public void givenFluxes_whenCombineLatestIsInvoked_thenCombineLatest() { Flux fluxOfIntegers = Flux.combineLatest( evenNumbers, oddNumbers, @@ -96,7 +96,7 @@ public class CombiningPublishersTest { } @Test - public void testCombineLatest1() { + public void givenFluxes_whenCombineLatestIsInvoked_thenCombineLatest1() { StepVerifier.create(Flux.combineLatest(obj -> (int) obj[1], evenNumbers, oddNumbers)) .expectNext(1) .expectNext(3) @@ -105,7 +105,7 @@ public class CombiningPublishersTest { } @Test - public void testMergeSequential() { + public void givenFluxes_whenMergeSequentialIsInvoked_thenMergeSequential() { Flux fluxOfIntegers = Flux.mergeSequential( evenNumbers, oddNumbers); @@ -122,7 +122,7 @@ public class CombiningPublishersTest { @Test - public void testMergeDelayError() { + public void givenFluxes_whenMergeDelayErrorIsInvoked_thenMergeDelayError() { Flux fluxOfIntegers = Flux.mergeDelayError(1, evenNumbers.delayElements(Duration.ofMillis(500L)), oddNumbers.delayElements(Duration.ofMillis(300L))); @@ -138,7 +138,7 @@ public class CombiningPublishersTest { } @Test - public void testMergeWith() { + public void givenFluxes_whenMergeWithIsInvoked_thenMergeWith() { Flux fluxOfIntegers = evenNumbers.mergeWith(oddNumbers); StepVerifier.create(fluxOfIntegers) @@ -152,7 +152,7 @@ public class CombiningPublishersTest { } @Test - public void testZip() { + public void givenFluxes_whenZipIsInvoked_thenZip() { Flux fluxOfIntegers = Flux.zip( evenNumbers, oddNumbers, @@ -166,7 +166,7 @@ public class CombiningPublishersTest { } @Test - public void testZipWith() { + public void givenFluxes_whenZipWithIsInvoked_thenZipWith() { Flux fluxOfIntegers = evenNumbers .zipWith(oddNumbers, (a, b) -> a * b); @@ -177,6 +177,4 @@ public class CombiningPublishersTest { .expectComplete() .verify(); } - - } diff --git a/rxjava/pom.xml b/rxjava/pom.xml index 0f950914ff..d88dfcaa9b 100644 --- a/rxjava/pom.xml +++ b/rxjava/pom.xml @@ -31,6 +31,19 @@ 1.0.0 + + io.reactivex + rxjava-string + 1.1.1 + + + + junit + junit + 4.12 + test + + com.jayway.awaitility awaitility diff --git a/rxjava/src/test/java/com/baeldung/rxjava/FlowableTest.java b/rxjava/src/test/java/com/baeldung/rxjava/FlowableTest.java new file mode 100644 index 0000000000..b9d1d64c24 --- /dev/null +++ b/rxjava/src/test/java/com/baeldung/rxjava/FlowableTest.java @@ -0,0 +1,93 @@ +package com.baeldung.rxjava; + +import io.reactivex.BackpressureStrategy; +import io.reactivex.Flowable; +import io.reactivex.FlowableOnSubscribe; +import io.reactivex.Observable; +import io.reactivex.exceptions.MissingBackpressureException; +import io.reactivex.schedulers.Schedulers; +import io.reactivex.subscribers.TestSubscriber; + +import org.junit.Test; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class FlowableTest { + + @Test public void whenFlowableIsCreated_thenItIsProperlyInitialized() { + Flowable integerFlowable = Flowable.just(1, 2, 3, 4); + assertNotNull(integerFlowable); + } + + @Test public void whenFlowableIsCreatedFromObservable_thenItIsProperlyInitialized() throws InterruptedException { + Observable integerObservable = Observable.just(1, 2, 3); + Flowable integerFlowable = integerObservable.toFlowable(BackpressureStrategy.BUFFER); + assertNotNull(integerFlowable); + + } + + @Test public void whenFlowableIsCreatedFromFlowableOnSubscribe_thenItIsProperlyInitialized() throws InterruptedException { + FlowableOnSubscribe flowableOnSubscribe = flowableEmitter -> flowableEmitter.onNext(1); + Flowable integerFlowable = Flowable.create(flowableOnSubscribe, BackpressureStrategy.BUFFER); + assertNotNull(integerFlowable); + } + + @Test public void thenAllValuesAreBufferedAndReceived() { + List testList = IntStream.range(0, 100000).boxed().collect(Collectors.toList()); + Observable observable = Observable.fromIterable(testList); + TestSubscriber testSubscriber = observable.toFlowable(BackpressureStrategy.BUFFER).observeOn(Schedulers.computation()).test(); + + testSubscriber.awaitTerminalEvent(); + + List receivedInts = testSubscriber.getEvents().get(0).stream().mapToInt(object -> (int) object).boxed().collect(Collectors.toList()); + + assertEquals(testList, receivedInts); + } + + @Test public void whenDropStrategyUsed_thenOnBackpressureDropped() { + List testList = IntStream.range(0, 100000).boxed().collect(Collectors.toList()); + + Observable observable = Observable.fromIterable(testList); + TestSubscriber testSubscriber = observable.toFlowable(BackpressureStrategy.DROP).observeOn(Schedulers.computation()).test(); + testSubscriber.awaitTerminalEvent(); + List receivedInts = testSubscriber.getEvents().get(0).stream().mapToInt(object -> (int) object).boxed().collect(Collectors.toList()); + + assertThat(receivedInts.size() < testList.size()); + assertThat(!receivedInts.contains(100000)); + } + + @Test public void whenMissingStrategyUsed_thenException() { + Observable observable = Observable.range(1, 100000); + TestSubscriber subscriber = observable.toFlowable(BackpressureStrategy.MISSING).observeOn(Schedulers.computation()).test(); + + subscriber.awaitTerminalEvent(); + subscriber.assertError(MissingBackpressureException.class); + } + + @Test public void whenErrorStrategyUsed_thenExceptionIsThrown() { + Observable observable = Observable.range(1, 100000); + TestSubscriber subscriber = observable.toFlowable(BackpressureStrategy.ERROR).observeOn(Schedulers.computation()).test(); + + subscriber.awaitTerminalEvent(); + subscriber.assertError(MissingBackpressureException.class); + } + + @Test public void whenLatestStrategyUsed_thenTheLastElementReceived() { + List testList = IntStream.range(0, 100000).boxed().collect(Collectors.toList()); + Observable observable = Observable.fromIterable(testList); + TestSubscriber testSubscriber = observable.toFlowable(BackpressureStrategy.LATEST).observeOn(Schedulers.computation()).test(); + + testSubscriber.awaitTerminalEvent(); + List receivedInts = testSubscriber.getEvents().get(0).stream().mapToInt(object -> (int) object).boxed().collect(Collectors.toList()); + + assertThat(receivedInts.size() < testList.size()); + assertThat(receivedInts.contains(100000)); + } + +} \ No newline at end of file diff --git a/rxjava/src/test/java/com/baeldung/rxjava/operators/RxStringOperatorsTest.java b/rxjava/src/test/java/com/baeldung/rxjava/operators/RxStringOperatorsTest.java new file mode 100644 index 0000000000..5e58b32d8b --- /dev/null +++ b/rxjava/src/test/java/com/baeldung/rxjava/operators/RxStringOperatorsTest.java @@ -0,0 +1,145 @@ +package com.baeldung.rxjava.operators; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Test; + +import rx.Observable; +import rx.observables.StringObservable; +import rx.observers.TestSubscriber; + + +public class RxStringOperatorsTest +{ + + @Test + public void givenStringObservable_whenFromInputStream_ThenSuccessfull() + { + //given + ByteArrayInputStream is = new ByteArrayInputStream("Lorem ipsum loream, Lorem ipsum lore".getBytes(StandardCharsets.UTF_8)); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.decode(StringObservable.from(is), StandardCharsets.UTF_8) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.assertValues("Lorem ipsum loream, Lorem ipsum lore"); + } + @Test + public void givenStringObservable_whenEncodingString_ThenSuccessfullObtainingByteStream() + { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.encode(sourceObservable, StandardCharsets.UTF_8) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.getOnNextEvents() + .stream() + .forEach(bytes -> Assert.assertTrue(Arrays.equals(bytes, "Lorem ipsum loream".getBytes(StandardCharsets.UTF_8)))); + } + + @Test + public void givenStringObservable_whenConcatenatingStrings_ThenSuccessfullObtainingSingleString() + { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream","Lorem ipsum lore"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.stringConcat(sourceObservable) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.assertValues("Lorem ipsum loreamLorem ipsum lore"); + } + + + @Test + public void givenStringObservable_whenDecodingByteArray_ThenSuccessfullObtainingStringStream() + { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream".getBytes(StandardCharsets.UTF_8)); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.decode(sourceObservable, StandardCharsets.UTF_8) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.assertValues("Lorem ipsum loream"); + } + + @Test + public void givenStringObservable_whenStringSplitted_ThenSuccessfullObtainingStringsStream() + { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream,Lorem ipsum lore"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.split(sourceObservable,",") + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(2); + subscriber.assertValues("Lorem ipsum loream", "Lorem ipsum lore"); + } + + @Test + public void givenStringObservable_whenSplittingByLine_ThenSuccessfullObtainingStringsStream() { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream\nLorem ipsum lore"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.byLine(sourceObservable) + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(2); + subscriber.assertValues("Lorem ipsum loream", "Lorem ipsum lore"); + } + + + @Test + public void givenStringObservable_whenJoiningStrings_ThenSuccessfullObtainingSingleString() { + //given + Observable sourceObservable = Observable.just("Lorem ipsum loream","Lorem ipsum lore"); + TestSubscriber subscriber = TestSubscriber.create(); + + // when + StringObservable.join(sourceObservable,",") + .subscribe(subscriber); + + // then + subscriber.assertCompleted(); + subscriber.assertNoErrors(); + subscriber.assertValueCount(1); + subscriber.assertValues("Lorem ipsum loream,Lorem ipsum lore"); + } + +} diff --git a/spring-5-security/pom.xml b/spring-5-security/pom.xml index 0a1d1f5df0..ffe6865704 100644 --- a/spring-5-security/pom.xml +++ b/spring-5-security/pom.xml @@ -12,7 +12,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.M7 + 2.0.0.RC2 diff --git a/spring-5-security/src/main/java/com/baeldung/passwordstorage/BaeldungPasswordEncoderSetup.java b/spring-5-security/src/main/java/com/baeldung/passwordstorage/BaeldungPasswordEncoderSetup.java new file mode 100644 index 0000000000..94987029db --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/passwordstorage/BaeldungPasswordEncoderSetup.java @@ -0,0 +1,35 @@ +package com.baeldung.passwordstorage; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; +import org.springframework.security.core.Authentication; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class BaeldungPasswordEncoderSetup { + + private final static Logger LOG = LoggerFactory.getLogger(BaeldungPasswordEncoderSetup.class); + + @Bean + public ApplicationListener authenticationSuccessListener(final PasswordEncoder encoder) { + + return (AuthenticationSuccessEvent event) -> { + final Authentication auth = event.getAuthentication(); + + if (auth instanceof UsernamePasswordAuthenticationToken && auth.getCredentials() != null) { + + final CharSequence clearTextPass = (CharSequence) auth.getCredentials(); // 1 + final String newPasswordHash = encoder.encode(clearTextPass); // 2 + + LOG.info("New password hash {} for user {}", newPasswordHash, auth.getName()); + + ((UsernamePasswordAuthenticationToken) auth).eraseCredentials(); // 3 + } + }; + } +} diff --git a/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageApplication.java b/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageApplication.java new file mode 100644 index 0000000000..173d979a45 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.passwordstorage; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PasswordStorageApplication { + + public static void main(String[] args) { + SpringApplication.run(PasswordStorageApplication.class, args); + } + +} diff --git a/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageWebSecurityConfigurer.java b/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageWebSecurityConfigurer.java new file mode 100644 index 0000000000..22ef2f0835 --- /dev/null +++ b/spring-5-security/src/main/java/com/baeldung/passwordstorage/PasswordStorageWebSecurityConfigurer.java @@ -0,0 +1,53 @@ +package com.baeldung.passwordstorage; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.DelegatingPasswordEncoder; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.crypto.password.StandardPasswordEncoder; +import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +@Configuration +public class PasswordStorageWebSecurityConfigurer extends WebSecurityConfigurerAdapter { + + + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.eraseCredentials(false) // 4 + .userDetailsService(getUserDefaultDetailsService()) + .passwordEncoder(passwordEncoder()); + } + + @Bean + public UserDetailsService getUserDefaultDetailsService() { + User testUser = new User("baeldung", "{noop}SpringSecurity5", Collections.emptyList()); + return new InMemoryUserDetailsManager(testUser); + } + + @Bean + public PasswordEncoder passwordEncoder() { + // set up the list of supported encoders and their prefixes + PasswordEncoder defaultEncoder = new StandardPasswordEncoder(); + Map encoders = new HashMap<>(); + encoders.put("bcrypt", new BCryptPasswordEncoder()); + encoders.put("scrypt", new SCryptPasswordEncoder()); + encoders.put("noop", NoOpPasswordEncoder.getInstance()); + + DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder("bcrypt", encoders); + passwordEncoder.setDefaultPasswordEncoderForMatches(defaultEncoder); + + return passwordEncoder; + } + +} diff --git a/spring-5/pom.xml b/spring-5/pom.xml index 19dd65d78f..3b21f86e60 100644 --- a/spring-5/pom.xml +++ b/spring-5/pom.xml @@ -14,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.0.M7 + 2.0.0.RC2 @@ -39,10 +39,14 @@ org.springframework.boot spring-boot-starter-webflux - + org.springframework.boot spring-boot-starter-hateoas + + org.springframework.boot + spring-boot-starter-thymeleaf + org.projectreactor reactor-spring diff --git a/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java b/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java index 287356256c..1670da54c3 100644 --- a/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java +++ b/spring-5/src/main/java/com/baeldung/execption/SpringExceptionApplication.java @@ -1,14 +1,14 @@ -package com.baeldung.execption; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication(exclude = SecurityAutoConfiguration.class) -@ComponentScan(basePackages = { "com.baeldung.execption" }) -public class SpringExceptionApplication { - public static void main(String[] args) { - SpringApplication.run(SpringExceptionApplication.class, args); - } +package com.baeldung.execption; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication(exclude = SecurityAutoConfiguration.class) +@ComponentScan(basePackages = { "com.baeldung.execption" }) +public class SpringExceptionApplication { + public static void main(String[] args) { + SpringApplication.run(SpringExceptionApplication.class, args); + } } \ No newline at end of file diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/Config.java b/spring-5/src/main/java/com/baeldung/sessionattrs/Config.java new file mode 100644 index 0000000000..9d5c9d9f42 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/Config.java @@ -0,0 +1,44 @@ +package com.baeldung.sessionattrs; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.core.Ordered; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.thymeleaf.templatemode.TemplateMode; +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; +import org.thymeleaf.templateresolver.ITemplateResolver; + +@EnableWebMvc +@Configuration +public class Config implements WebMvcConfigurer { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/").setViewName("index"); + registry.setOrder(Ordered.HIGHEST_PRECEDENCE); + } + + @Bean + @Scope( + value = WebApplicationContext.SCOPE_SESSION, + proxyMode = ScopedProxyMode.TARGET_CLASS) + public TodoList todos() { + return new TodoList(); + } + + @Bean + public ITemplateResolver templateResolver() { + ClassLoaderTemplateResolver resolver + = new ClassLoaderTemplateResolver(); + resolver.setPrefix("templates/sessionattrs/"); + resolver.setSuffix(".html"); + resolver.setTemplateMode(TemplateMode.HTML); + resolver.setCharacterEncoding("UTF-8"); + return resolver; + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/SessionAttrsApplication.java b/spring-5/src/main/java/com/baeldung/sessionattrs/SessionAttrsApplication.java new file mode 100644 index 0000000000..7b9f8a700f --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/SessionAttrsApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.sessionattrs; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; + +@SpringBootApplication( + exclude = {SecurityAutoConfiguration.class, + DataSourceAutoConfiguration.class}) +public class SessionAttrsApplication { + + public static void main(String[] args) { + SpringApplication.run(SessionAttrsApplication.class, args); + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxy.java b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxy.java new file mode 100644 index 0000000000..0c3bd6c8b6 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxy.java @@ -0,0 +1,45 @@ +package com.baeldung.sessionattrs; + +import java.time.LocalDateTime; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping("/scopedproxy") +public class TodoControllerWithScopedProxy { + + private TodoList todos; + + public TodoControllerWithScopedProxy(TodoList todos) { + this.todos = todos; + } + + @GetMapping("/form") + public String showForm(Model model) { + if (!todos.isEmpty()) { + model.addAttribute("todo", todos.peekLast()); + } else { + model.addAttribute("todo", new TodoItem()); + } + + return "scopedproxyform"; + } + + @PostMapping("/form") + public String create(@ModelAttribute TodoItem todo) { + todo.setCreateDate(LocalDateTime.now()); + todos.add(todo); + return "redirect:/scopedproxy/todos.html"; + } + + @GetMapping("/todos.html") + public String list(Model model) { + model.addAttribute("todos", todos); + return "scopedproxytodos"; + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributes.java b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributes.java new file mode 100644 index 0000000000..fc7e57b1db --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributes.java @@ -0,0 +1,55 @@ +package com.baeldung.sessionattrs; + +import java.time.LocalDateTime; + +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.SessionAttributes; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; +import org.springframework.web.servlet.view.RedirectView; + +@Controller +@RequestMapping("/sessionattributes") +@SessionAttributes("todos") +public class TodoControllerWithSessionAttributes { + + @GetMapping("/form") + public String showForm( + Model model, + @ModelAttribute("todos") TodoList todos) { + if (!todos.isEmpty()) { + model.addAttribute("todo", todos.peekLast()); + } else { + model.addAttribute("todo", new TodoItem()); + } + return "sessionattributesform"; + } + + @PostMapping("/form") + public RedirectView create( + @ModelAttribute TodoItem todo, + @ModelAttribute("todos") TodoList todos, + RedirectAttributes attributes) { + todo.setCreateDate(LocalDateTime.now()); + todos.add(todo); + attributes.addFlashAttribute("todos", todos); + return new RedirectView("/sessionattributes/todos.html"); + } + + @GetMapping("/todos.html") + public String list( + Model model, + @ModelAttribute("todos") TodoList todos) { + model.addAttribute("todos", todos); + return "sessionattributestodos"; + } + + @ModelAttribute("todos") + public TodoList todos() { + return new TodoList(); + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/TodoItem.java b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoItem.java new file mode 100644 index 0000000000..619d61d5f0 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoItem.java @@ -0,0 +1,39 @@ +package com.baeldung.sessionattrs; + +import java.time.LocalDateTime; + +public class TodoItem { + + private String description; + private LocalDateTime createDate; + + public TodoItem(String description, LocalDateTime createDate) { + this.description = description; + this.createDate = createDate; + } + + public TodoItem() { + // default no arg constructor + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public LocalDateTime getCreateDate() { + return createDate; + } + + public void setCreateDate(LocalDateTime createDate) { + this.createDate = createDate; + } + + @Override + public String toString() { + return "TodoItem [description=" + description + ", createDate=" + createDate + "]"; + } +} diff --git a/spring-5/src/main/java/com/baeldung/sessionattrs/TodoList.java b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoList.java new file mode 100644 index 0000000000..cad7811da4 --- /dev/null +++ b/spring-5/src/main/java/com/baeldung/sessionattrs/TodoList.java @@ -0,0 +1,8 @@ +package com.baeldung.sessionattrs; + +import java.util.ArrayDeque; + +@SuppressWarnings("serial") +public class TodoList extends ArrayDeque{ + +} diff --git a/spring-5/src/main/resources/templates/sessionattrs/index.html b/spring-5/src/main/resources/templates/sessionattrs/index.html new file mode 100644 index 0000000000..72427cd62b --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/index.html @@ -0,0 +1,27 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Session Scope in Spring MVC - Example

+

+
+ + + \ No newline at end of file diff --git a/spring-5/src/main/resources/templates/sessionattrs/scopedproxyform.html b/spring-5/src/main/resources/templates/sessionattrs/scopedproxyform.html new file mode 100644 index 0000000000..e72651556b --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/scopedproxyform.html @@ -0,0 +1,27 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Scoped Proxy Example

+

+
+
+
Enter a TODO
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/spring-5/src/main/resources/templates/sessionattrs/scopedproxytodos.html b/spring-5/src/main/resources/templates/sessionattrs/scopedproxytodos.html new file mode 100644 index 0000000000..5493b5cf64 --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/scopedproxytodos.html @@ -0,0 +1,48 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Scoped Proxy Example

+

+
+
+
+
+ Add New +
+
+
+
+
+
TODO List
+ + + + + + + + + + + +
DescriptionCreate Date
DescriptionCreate Date
+
+
+
+
+ + \ No newline at end of file diff --git a/spring-5/src/main/resources/templates/sessionattrs/sessionattributesform.html b/spring-5/src/main/resources/templates/sessionattrs/sessionattributesform.html new file mode 100644 index 0000000000..28e1d5d2c1 --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/sessionattributesform.html @@ -0,0 +1,27 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Session Attributes Example

+

+
+
+
Enter a TODO
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/spring-5/src/main/resources/templates/sessionattrs/sessionattributestodos.html b/spring-5/src/main/resources/templates/sessionattrs/sessionattributestodos.html new file mode 100644 index 0000000000..4bae12ffb9 --- /dev/null +++ b/spring-5/src/main/resources/templates/sessionattrs/sessionattributestodos.html @@ -0,0 +1,48 @@ + + + + Session Scope in Spring MVC + + + + + + + +
+

+

Session Attributes Example

+

+
+
+
+
+ Add New +
+
+
+
+
+
TODO List
+ + + + + + + + + + + +
DescriptionCreate Date
DescriptionCreate Date
+
+
+
+
+ + \ No newline at end of file diff --git a/spring-5/src/test/java/com/baeldung/sessionattrs/SessionAttrsApplicationTests.java b/spring-5/src/test/java/com/baeldung/sessionattrs/SessionAttrsApplicationTests.java new file mode 100644 index 0000000000..0b15a2114d --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/sessionattrs/SessionAttrsApplicationTests.java @@ -0,0 +1,16 @@ +package com.baeldung.sessionattrs; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SessionAttrsApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-5/src/test/java/com/baeldung/sessionattrs/TestConfig.java b/spring-5/src/test/java/com/baeldung/sessionattrs/TestConfig.java new file mode 100644 index 0000000000..07d65dd7c2 --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/sessionattrs/TestConfig.java @@ -0,0 +1,17 @@ +package com.baeldung.sessionattrs; + +import org.springframework.beans.factory.config.CustomScopeConfigurer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.SimpleThreadScope; + +@Configuration +public class TestConfig { + + @Bean + public CustomScopeConfigurer customScopeConfigurer() { + CustomScopeConfigurer configurer = new CustomScopeConfigurer(); + configurer.addScope("session", new SimpleThreadScope()); + return configurer; + } +} diff --git a/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxyTest.java b/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxyTest.java new file mode 100644 index 0000000000..3db7c183ce --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithScopedProxyTest.java @@ -0,0 +1,68 @@ +package com.baeldung.sessionattrs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.util.StringUtils; +import org.springframework.web.context.WebApplicationContext; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +@Import(TestConfig.class) +public class TodoControllerWithScopedProxyTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private WebApplicationContext wac; + + @Before + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac) + .build(); + } + + @Test + public void whenFirstRequest_thenContainsAllCategoriesAndUnintializedTodo() throws Exception { + MvcResult result = mockMvc.perform(get("/scopedproxy/form")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("todo")) + .andReturn(); + + TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo"); + assertTrue(StringUtils.isEmpty(item.getDescription())); + } + + @Test + public void whenSubmit_thenSubsequentFormRequestContainsMostRecentTodo() throws Exception { + mockMvc.perform(post("/scopedproxy/form") + .param("description", "newtodo")) + .andExpect(status().is3xxRedirection()) + .andReturn(); + + MvcResult result = mockMvc.perform(get("/scopedproxy/form")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("todo")) + .andReturn(); + TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo"); + assertEquals("newtodo", item.getDescription()); + } + +} diff --git a/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributesTest.java b/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributesTest.java new file mode 100644 index 0000000000..a09fac9699 --- /dev/null +++ b/spring-5/src/test/java/com/baeldung/sessionattrs/TodoControllerWithSessionAttributesTest.java @@ -0,0 +1,68 @@ +package com.baeldung.sessionattrs; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.util.StringUtils; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.servlet.FlashMap; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +public class TodoControllerWithSessionAttributesTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private WebApplicationContext wac; + + @Before + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac) + .build(); + } + + @Test + public void whenFirstRequest_thenContainsUnintializedTodo() throws Exception { + MvcResult result = mockMvc.perform(get("/sessionattributes/form")) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("todo")) + .andReturn(); + + TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo"); + assertTrue(StringUtils.isEmpty(item.getDescription())); + } + + @Test + public void whenSubmit_thenSubsequentFormRequestContainsMostRecentTodo() throws Exception { + FlashMap flashMap = mockMvc.perform(post("/sessionattributes/form") + .param("description", "newtodo")) + .andExpect(status().is3xxRedirection()) + .andReturn().getFlashMap(); + + MvcResult result = mockMvc.perform(get("/sessionattributes/form") + .sessionAttrs(flashMap)) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("todo")) + .andReturn(); + TodoItem item = (TodoItem) result.getModelAndView().getModel().get("todo"); + assertEquals("newtodo", item.getDescription()); + } + +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/ChunksConfig.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/ChunksConfig.java new file mode 100644 index 0000000000..601ffb7f27 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/ChunksConfig.java @@ -0,0 +1,90 @@ +package org.baeldung.taskletsvschunks.config; + +import org.baeldung.taskletsvschunks.chunks.LineProcessor; +import org.baeldung.taskletsvschunks.chunks.LineReader; +import org.baeldung.taskletsvschunks.chunks.LinesWriter; +import org.baeldung.taskletsvschunks.model.Line; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemReader; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; + +@Configuration +@EnableBatchProcessing +public class ChunksConfig { + + @Autowired private JobBuilderFactory jobs; + + @Autowired private StepBuilderFactory steps; + + @Bean + public JobLauncherTestUtils jobLauncherTestUtils() { + return new JobLauncherTestUtils(); + } + + @Bean + public JobRepository jobRepository() throws Exception { + MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(); + factory.setTransactionManager(transactionManager()); + return (JobRepository) factory.getObject(); + } + + @Bean + public PlatformTransactionManager transactionManager() { + return new ResourcelessTransactionManager(); + } + + @Bean + public JobLauncher jobLauncher() throws Exception { + SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); + jobLauncher.setJobRepository(jobRepository()); + return jobLauncher; + } + + @Bean + public ItemReader itemReader() { + return new LineReader(); + } + + @Bean + public ItemProcessor itemProcessor() { + return new LineProcessor(); + } + + @Bean + public ItemWriter itemWriter() { + return new LinesWriter(); + } + + @Bean + protected Step processLines(ItemReader reader, ItemProcessor processor, ItemWriter writer) { + return steps.get("processLines"). chunk(2) + .reader(reader) + .processor(processor) + .writer(writer) + .build(); + } + + @Bean + public Job job() { + return jobs + .get("chunksJob") + .start(processLines(itemReader(), itemProcessor(), itemWriter())) + .build(); + } + +} diff --git a/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/TaskletsConfig.java b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/TaskletsConfig.java new file mode 100644 index 0000000000..b9d06d2639 --- /dev/null +++ b/spring-batch/src/main/java/org/baeldung/taskletsvschunks/config/TaskletsConfig.java @@ -0,0 +1,103 @@ +package org.baeldung.taskletsvschunks.config; + +import org.baeldung.taskletsvschunks.tasklets.LinesProcessor; +import org.baeldung.taskletsvschunks.tasklets.LinesReader; +import org.baeldung.taskletsvschunks.tasklets.LinesWriter; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.launch.support.SimpleJobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean; +import org.springframework.batch.support.transaction.ResourcelessTransactionManager; +import org.springframework.batch.test.JobLauncherTestUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.PlatformTransactionManager; + +@Configuration +@EnableBatchProcessing +public class TaskletsConfig { + + @Autowired private JobBuilderFactory jobs; + + @Autowired private StepBuilderFactory steps; + + @Bean + public JobLauncherTestUtils jobLauncherTestUtils() { + return new JobLauncherTestUtils(); + } + + @Bean + public JobRepository jobRepository() throws Exception { + MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(); + factory.setTransactionManager(transactionManager()); + return (JobRepository) factory.getObject(); + } + + @Bean + public PlatformTransactionManager transactionManager() { + return new ResourcelessTransactionManager(); + } + + @Bean + public JobLauncher jobLauncher() throws Exception { + SimpleJobLauncher jobLauncher = new SimpleJobLauncher(); + jobLauncher.setJobRepository(jobRepository()); + return jobLauncher; + } + + @Bean + public LinesReader linesReader() { + return new LinesReader(); + } + + @Bean + public LinesProcessor linesProcessor() { + return new LinesProcessor(); + } + + @Bean + public LinesWriter linesWriter() { + return new LinesWriter(); + } + + @Bean + protected Step readLines() { + return steps + .get("readLines") + .tasklet(linesReader()) + .build(); + } + + @Bean + protected Step processLines() { + return steps + .get("processLines") + .tasklet(linesProcessor()) + .build(); + } + + @Bean + protected Step writeLines() { + return steps + .get("writeLines") + .tasklet(linesWriter()) + .build(); + } + + @Bean + public Job job() { + return jobs + .get("taskletsJob") + .start(readLines()) + .next(processLines()) + .next(writeLines()) + .build(); + } + +} diff --git a/spring-batch/src/main/resources/taskletsvschunks/chunks.xml b/spring-batch/src/main/resources/taskletsvschunks/chunks.xml deleted file mode 100644 index f4b77ac10c..0000000000 --- a/spring-batch/src/main/resources/taskletsvschunks/chunks.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/spring-batch/src/main/resources/taskletsvschunks/tasklets.xml b/spring-batch/src/main/resources/taskletsvschunks/tasklets.xml deleted file mode 100644 index 34ce2944bc..0000000000 --- a/spring-batch/src/main/resources/taskletsvschunks/tasklets.xml +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java index 34b6315dc4..2a71970637 100644 --- a/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java +++ b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/chunks/ChunksTest.java @@ -1,5 +1,6 @@ package org.baeldung.taskletsvschunks.chunks; +import org.baeldung.taskletsvschunks.config.ChunksConfig; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -11,7 +12,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = "classpath:/taskletsvschunks/chunks.xml") +@ContextConfiguration(classes = ChunksConfig.class) public class ChunksTest { @Autowired private JobLauncherTestUtils jobLauncherTestUtils; diff --git a/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java index 53731feed4..20379b58fe 100644 --- a/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java +++ b/spring-batch/src/test/java/org/baeldung/taskletsvschunks/tasklets/TaskletsTest.java @@ -1,5 +1,6 @@ package org.baeldung.taskletsvschunks.tasklets; +import org.baeldung.taskletsvschunks.config.TaskletsConfig; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -11,7 +12,7 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = "classpath:/taskletsvschunks/tasklets.xml") +@ContextConfiguration(classes = TaskletsConfig.class) public class TaskletsTest { @Autowired private JobLauncherTestUtils jobLauncherTestUtils; diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/.gitignore b/spring-cloud/spring-cloud-task/springcloudtaskbatch/.gitignore new file mode 100644 index 0000000000..f675857856 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/.gitignore @@ -0,0 +1,2 @@ +/target/ +/.settings/ \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml b/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml new file mode 100644 index 0000000000..4805f5296c --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/pom.xml @@ -0,0 +1,81 @@ + + 4.0.0 + org.baeldung.cloud + springcloudtask + 0.0.1-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 1.5.10.RELEASE + + + + + com.baeldung.TaskDemo + UTF-8 + UTF-8 + 1.8 + 1.2.2.RELEASE + + + + + + + org.springframework.boot + spring-boot-starter + + + org.springframework.boot + spring-boot-starter-data-jpa + + + mysql + mysql-connector-java + + + org.springframework.cloud + spring-cloud-starter-task + + + + org.springframework.cloud + spring-cloud-task-core + + + + org.springframework.boot + spring-boot-starter-batch + + + + org.springframework.cloud + spring-cloud-task-batch + + + + + + + org.springframework.cloud + spring-cloud-task-dependencies + ${spring-cloud-task.version} + pom + import + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/HelloWorldTaskConfigurer.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/HelloWorldTaskConfigurer.java new file mode 100644 index 0000000000..dc2ba53138 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/HelloWorldTaskConfigurer.java @@ -0,0 +1,14 @@ +package com.baeldung.task; + +import javax.sql.DataSource; + +import org.springframework.cloud.task.configuration.DefaultTaskConfigurer; + +public class HelloWorldTaskConfigurer + extends + DefaultTaskConfigurer { + + public HelloWorldTaskConfigurer(DataSource dataSource) { + super(dataSource); + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/JobConfiguration.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/JobConfiguration.java new file mode 100644 index 0000000000..6c215ad53d --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/JobConfiguration.java @@ -0,0 +1,105 @@ +package com.baeldung.task; + +import java.util.Arrays; +import java.util.List; +import java.util.logging.Logger; + +import org.springframework.batch.core.Job; +import org.springframework.batch.core.Step; +import org.springframework.batch.core.StepContribution; +import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; +import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; +import org.springframework.batch.core.scope.context.ChunkContext; +import org.springframework.batch.core.step.tasklet.Tasklet; +import org.springframework.batch.item.ItemProcessor; +import org.springframework.batch.item.ItemWriter; +import org.springframework.batch.item.support.ListItemReader; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class JobConfiguration { + + private final static Logger LOGGER = Logger + .getLogger(JobConfiguration.class.getName()); + + @Autowired + private JobBuilderFactory jobBuilderFactory; + + @Autowired + private StepBuilderFactory stepBuilderFactory; + + @Bean + public Step step1() { + return this.stepBuilderFactory.get("job1step1") + .tasklet(new Tasklet() { + @Override + public RepeatStatus execute( + StepContribution contribution, + ChunkContext chunkContext) + throws Exception { + LOGGER.info("Tasklet has run"); + return RepeatStatus.FINISHED; + } + }).build(); + } + + @Bean + public Step step2() { + return this.stepBuilderFactory + .get("job1step2") + . chunk(3) + .reader( + new ListItemReader<>(Arrays.asList("7", + "2", "3", "10", "5", "6"))) + .processor( + new ItemProcessor() { + @Override + public String process(String item) + throws Exception { + LOGGER.info("Processing of chunks"); + return String.valueOf(Integer + .parseInt(item) * -1); + } + }) + .writer(new ItemWriter() { + @Override + public void write( + List items) + throws Exception { + for (String item : items) { + LOGGER.info(">> " + item); + } + } + }).build(); + } + + @Bean + public Job job1() { + return this.jobBuilderFactory.get("job1") + .start(step1()) + .next(step2()) + .build(); + } + + @Bean + public Job job2() { + return jobBuilderFactory.get("job2") + .start(stepBuilderFactory.get("job2step1") + .tasklet(new Tasklet() { + @Override + public RepeatStatus execute( + StepContribution contribution, + ChunkContext chunkContext) + throws Exception { + LOGGER + .info("This job is from Baeldung"); + return RepeatStatus.FINISHED; + } + }) + .build()) + .build(); + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java new file mode 100644 index 0000000000..be2a173589 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskDemo.java @@ -0,0 +1,56 @@ +package com.baeldung.task; + +import java.util.logging.Logger; + +import javax.sql.DataSource; + +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.task.configuration.EnableTask; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +@SpringBootApplication +@EnableTask +@EnableBatchProcessing +public class TaskDemo { + + private final static Logger LOGGER = Logger + .getLogger(TaskDemo.class.getName()); + + @Autowired + private DataSource dataSource; + + @Bean + public HelloWorldTaskConfigurer getTaskConfigurer() + { + return new HelloWorldTaskConfigurer(dataSource); + } + + @Bean + public TaskListener taskListener() { + return new TaskListener(); + } + + public static void main(String[] args) { + SpringApplication.run(TaskDemo.class, args); + } + + @Component + public static class HelloWorldApplicationRunner + implements + ApplicationRunner { + + @Override + public void run(ApplicationArguments arg0) + throws Exception { + // TODO Auto-generated method stub + LOGGER + .info("Hello World from Spring Cloud Task!"); + } + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskListener.java b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskListener.java new file mode 100644 index 0000000000..8250153b66 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/java/com/baeldung/task/TaskListener.java @@ -0,0 +1,31 @@ +package com.baeldung.task; + +import java.util.logging.Logger; + +import org.springframework.cloud.task.listener.TaskExecutionListener; +import org.springframework.cloud.task.repository.TaskExecution; + +public class TaskListener implements TaskExecutionListener { + + private final static Logger LOGGER = Logger + .getLogger(TaskListener.class.getName()); + + @Override + public void onTaskEnd(TaskExecution arg0) { + // TODO Auto-generated method stub + LOGGER.info("End of Task"); + } + + @Override + public void onTaskFailed(TaskExecution arg0, + Throwable arg1) { + // TODO Auto-generated method stub + + } + + @Override + public void onTaskStartup(TaskExecution arg0) { + // TODO Auto-generated method stub + LOGGER.info("Task Startup"); + } +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml new file mode 100644 index 0000000000..1187c12fe7 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtaskbatch/src/main/resources/application.yml @@ -0,0 +1,26 @@ +logging: + level: + org: + springframework: + cloud: + task=DEBUG + +spring: + application: + name=helloWorld + datasource: + url: jdbc:mysql://localhost:3306/springcloud?useSSL=false + username: root + password: + jpa: + hibernate: + ddl-auto: create-drop + properties: + hibernate: + dialect: org.hibernate.dialect.MySQL5Dialect + batch: + initialize-schema: always +maven: + remoteRepositories: + springRepo: + url: https://repo.spring.io/libs-snapshot \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/.gitignore b/spring-cloud/spring-cloud-task/springcloudtasksink/.gitignore new file mode 100644 index 0000000000..2af7cefb0a --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml b/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml new file mode 100644 index 0000000000..b717fffc7c --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/pom.xml @@ -0,0 +1,88 @@ + + + 4.0.0 + + com.baeldung + SpringCloudTaskSink + 0.0.1-SNAPSHOT + jar + + SpringCloudTaskSink + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.5.10.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + 1.2.2.RELEASE + Edgware.SR2 + + + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + + + org.springframework.cloud + spring-cloud-starter-task + + + org.springframework.cloud + spring-cloud-stream-test-support + test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.cloud + spring-cloud-deployer-local + 1.3.0.RELEASE + + + + + + + org.springframework.cloud + spring-cloud-task-dependencies + ${spring-cloud-task.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplication.java b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplication.java new file mode 100644 index 0000000000..62085e5fa5 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplication.java @@ -0,0 +1,16 @@ +package com.baeldung.SpringCloudTaskFinal; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.task.launcher.annotation.EnableTaskLauncher; + +@SpringBootApplication +@EnableTaskLauncher +public class SpringCloudTaskSinkApplication { + + public static void main(String[] args) { + SpringApplication.run( + SpringCloudTaskSinkApplication.class, args); + } + +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/TaskSinkConfiguration.java b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/TaskSinkConfiguration.java new file mode 100644 index 0000000000..638de58ecb --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/java/com/baeldung/SpringCloudTaskFinal/TaskSinkConfiguration.java @@ -0,0 +1,18 @@ +package com.baeldung.SpringCloudTaskFinal; + +import static org.mockito.Mockito.mock; + +import org.springframework.cloud.deployer.spi.task.TaskLauncher; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +@Configuration +public class TaskSinkConfiguration { + + @Bean + public TaskLauncher taskLauncher() { + return mock(TaskLauncher.class); + } + +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties new file mode 100644 index 0000000000..1660dc8516 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/src/main/resources/application.properties @@ -0,0 +1 @@ +maven.remoteRepositories.springRepo.url=https://repo.spring.io/libs-snapshot \ No newline at end of file diff --git a/spring-cloud/spring-cloud-task/springcloudtasksink/src/test/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplicationTests.java b/spring-cloud/spring-cloud-task/springcloudtasksink/src/test/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplicationTests.java new file mode 100644 index 0000000000..1f47eada14 --- /dev/null +++ b/spring-cloud/spring-cloud-task/springcloudtasksink/src/test/java/com/baeldung/SpringCloudTaskFinal/SpringCloudTaskSinkApplicationTests.java @@ -0,0 +1,72 @@ +package com.baeldung.SpringCloudTaskFinal; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.deployer.spi.core.AppDeploymentRequest; +import org.springframework.cloud.deployer.spi.task.TaskLauncher; +import org.springframework.cloud.stream.messaging.Sink; +import org.springframework.cloud.task.launcher.TaskLaunchRequest; +import org.springframework.context.ApplicationContext; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.verify; + +@RunWith(SpringRunner.class) +@SpringBootTest( + classes = SpringCloudTaskSinkApplication.class) +public class SpringCloudTaskSinkApplicationTests { + + @Autowired + ApplicationContext context; + + @Autowired + private Sink sink; + + @Test + public void testTaskLaunch() throws IOException { + + TaskLauncher taskLauncher = + context.getBean(TaskLauncher.class); + + Map prop = new HashMap(); + prop.put("server.port", "0"); + TaskLaunchRequest request = new TaskLaunchRequest( + "maven://org.springframework.cloud.task.app:" + + "timestamp-task:jar:1.0.1.RELEASE", null, + prop, + null, null); + GenericMessage message = new GenericMessage( + request); + this.sink.input().send(message); + + ArgumentCaptor deploymentRequest = ArgumentCaptor + .forClass(AppDeploymentRequest.class); + + verify(taskLauncher).launch( + deploymentRequest.capture()); + + AppDeploymentRequest actualRequest = deploymentRequest + .getValue(); + + // Verifying the co-ordinate of launched Task here. + assertTrue(actualRequest.getCommandlineArguments() + .isEmpty()); + assertEquals("0", actualRequest.getDefinition() + .getProperties().get("server.port")); + assertTrue(actualRequest + .getResource() + .toString() + .contains( + "org.springframework.cloud.task.app:timestamp-task:jar:1.0.1.RELEASE")); + } +} \ No newline at end of file diff --git a/spring-mvc-kotlin/pom.xml b/spring-mvc-kotlin/pom.xml index 2d1dac5e29..28a5681c03 100644 --- a/spring-mvc-kotlin/pom.xml +++ b/spring-mvc-kotlin/pom.xml @@ -17,38 +17,64 @@ war + + UTF-8 + 5.2.13.Final + 1.2.21 + 4.3.10.RELEASE + 3.0.7.RELEASE + 1.4.196 + + org.jetbrains.kotlin - kotlin-stdlib-jre8 - 1.1.4 + kotlin-stdlib-jdk8 + ${kotlin.version} org.springframework spring-web - 4.3.10.RELEASE + ${spring.version} org.springframework spring-webmvc - 4.3.10.RELEASE + ${spring.version} org.thymeleaf thymeleaf - 3.0.7.RELEASE + ${thymeleaf.version} org.thymeleaf thymeleaf-spring4 - 3.0.7.RELEASE + ${thymeleaf.version} + + + org.hibernate + hibernate-core + ${hibernate.version} + + + org.hibernate + hibernate-testing + ${hibernate.version} + test + + + com.h2database + h2 + ${h2.version} + test org.springframework spring-test - 4.3.10.RELEASE + ${spring.version} test @@ -60,10 +86,11 @@ kotlin-maven-plugin org.jetbrains.kotlin - 1.1.4 + ${kotlin.version} spring + jpa 1.8 @@ -87,7 +114,12 @@ org.jetbrains.kotlin kotlin-maven-allopen - 1.1.4-3 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-maven-noarg + ${kotlin.version} diff --git a/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/jpa/Person.kt b/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/jpa/Person.kt new file mode 100644 index 0000000000..801bd1b0a5 --- /dev/null +++ b/spring-mvc-kotlin/src/main/kotlin/com/baeldung/kotlin/jpa/Person.kt @@ -0,0 +1,15 @@ +package com.baeldung.jpa + +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.Table + +@Entity +@Table(name = "person") +data class Person( + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + val id: Int, + val name: String) \ No newline at end of file diff --git a/spring-mvc-kotlin/src/test/kotlin/com/baeldung/kotlin/jpa/HibernateKotlinIntegrationTest.kt b/spring-mvc-kotlin/src/test/kotlin/com/baeldung/kotlin/jpa/HibernateKotlinIntegrationTest.kt new file mode 100644 index 0000000000..8f54373406 --- /dev/null +++ b/spring-mvc-kotlin/src/test/kotlin/com/baeldung/kotlin/jpa/HibernateKotlinIntegrationTest.kt @@ -0,0 +1,44 @@ +package com.baeldung.kotlin.jpa + +import com.baeldung.jpa.Person +import org.hibernate.cfg.Configuration +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase +import org.hibernate.testing.transaction.TransactionUtil.doInHibernate +import org.junit.Assert.assertTrue +import org.junit.Test +import java.io.IOException +import java.util.* + + +class HibernateKotlinIntegrationTest : BaseCoreFunctionalTestCase() { + + private val properties: Properties + @Throws(IOException::class) + get() { + val properties = Properties() + properties.load(javaClass.classLoader.getResourceAsStream("hibernate.properties")) + return properties + } + + override fun getAnnotatedClasses(): Array> { + return arrayOf(Person::class.java) + } + + override fun configure(configuration: Configuration) { + super.configure(configuration) + configuration.properties = properties + } + + @Test + fun givenPerson_whenSaved_thenFound() { + val personToSave = Person(0, "John") + doInHibernate(({ this.sessionFactory() }), { session -> + session.persist(personToSave) + assertTrue(session.contains(personToSave)) + }) + doInHibernate(({ this.sessionFactory() }), { session -> + val personFound = session.find(Person::class.java, personToSave.id) + assertTrue(personToSave == personFound) + }) + } +} \ No newline at end of file diff --git a/spring-mvc-kotlin/src/test/resources/hibernate.properties b/spring-mvc-kotlin/src/test/resources/hibernate.properties new file mode 100644 index 0000000000..7b8764637b --- /dev/null +++ b/spring-mvc-kotlin/src/test/resources/hibernate.properties @@ -0,0 +1,9 @@ +hibernate.connection.driver_class=org.h2.Driver +hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1 +hibernate.connection.username=sa +hibernate.connection.autocommit=true +jdbc.password= + +hibernate.dialect=org.hibernate.dialect.H2Dialect +hibernate.show_sql=true +hibernate.hbm2ddl.auto=create-drop \ No newline at end of file diff --git a/spring-security-openid/pom.xml b/spring-security-openid/pom.xml index 4c8112a163..aeabb161c9 100644 --- a/spring-security-openid/pom.xml +++ b/spring-security-openid/pom.xml @@ -46,6 +46,11 @@ 1.0.9.RELEASE
+ + com.auth0 + jwks-rsa + 0.3.0 + diff --git a/spring-security-openid/src/main/java/org/baeldung/security/OpenIdConnectFilter.java b/spring-security-openid/src/main/java/org/baeldung/security/OpenIdConnectFilter.java index c0970ab3cf..f12169cb27 100644 --- a/spring-security-openid/src/main/java/org/baeldung/security/OpenIdConnectFilter.java +++ b/spring-security-openid/src/main/java/org/baeldung/security/OpenIdConnectFilter.java @@ -1,12 +1,16 @@ package org.baeldung.security; import java.io.IOException; +import java.net.URL; +import java.security.interfaces.RSAPublicKey; +import java.util.Date; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -14,16 +18,28 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.jwt.Jwt; import org.springframework.security.jwt.JwtHelper; +import org.springframework.security.jwt.crypto.sign.RsaVerifier; import org.springframework.security.oauth2.client.OAuth2RestOperations; import org.springframework.security.oauth2.client.OAuth2RestTemplate; import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import com.auth0.jwk.Jwk; +import com.auth0.jwk.JwkProvider; +import com.auth0.jwk.UrlJwkProvider; import com.fasterxml.jackson.databind.ObjectMapper; public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter { + @Value("${google.clientId}") + private String clientId; + + @Value("${google.issuer}") + private String issuer; + + @Value("${google.jwkUrl}") + private String jwkUrl; + public OAuth2RestOperations restTemplate; public OpenIdConnectFilter(String defaultFilterProcessesUrl) { @@ -42,19 +58,35 @@ public class OpenIdConnectFilter extends AbstractAuthenticationProcessingFilter } try { final String idToken = accessToken.getAdditionalInformation().get("id_token").toString(); - final Jwt tokenDecoded = JwtHelper.decode(idToken); - System.out.println("===== : " + tokenDecoded.getClaims()); - + String kid = JwtHelper.headers(idToken) + .get("kid"); + final Jwt tokenDecoded = JwtHelper.decodeAndVerify(idToken, verifier(kid)); final Map authInfo = new ObjectMapper().readValue(tokenDecoded.getClaims(), Map.class); - + verifyClaims(authInfo); final OpenIdConnectUserDetails user = new OpenIdConnectUserDetails(authInfo, accessToken); return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities()); - } catch (final InvalidTokenException e) { + } catch (final Exception e) { throw new BadCredentialsException("Could not obtain user details from token", e); } } + public void verifyClaims(Map claims) { + int exp = (int) claims.get("exp"); + Date expireDate = new Date(exp * 1000L); + Date now = new Date(); + if (expireDate.before(now) || !claims.get("iss").equals(issuer) || !claims.get("aud").equals(clientId)) { + throw new RuntimeException("Invalid claims"); + } + } + + + private RsaVerifier verifier(String kid) throws Exception { + JwkProvider provider = new UrlJwkProvider(new URL(jwkUrl)); + Jwk jwk = provider.get(kid); + return new RsaVerifier((RSAPublicKey) jwk.getPublicKey()); + } + public void setRestTemplate(OAuth2RestTemplate restTemplate2) { restTemplate = restTemplate2; diff --git a/spring-security-openid/src/main/resources/application.properties.sample.properties b/spring-security-openid/src/main/resources/application.properties.sample.properties index 3b4f7716f0..49022bf280 100644 --- a/spring-security-openid/src/main/resources/application.properties.sample.properties +++ b/spring-security-openid/src/main/resources/application.properties.sample.properties @@ -3,4 +3,6 @@ google.clientId=TODO google.clientSecret=TODO google.accessTokenUri=https://www.googleapis.com/oauth2/v3/token google.userAuthorizationUri=https://accounts.google.com/o/oauth2/auth -google.redirectUri=http://localhost:8081/google-login \ No newline at end of file +google.redirectUri=http://localhost:8081/google-login +google.issuer=accounts.google.com +google.jwkUrl=https://www.googleapis.com/oauth2/v2/certs \ No newline at end of file diff --git a/vavr/src/test/java/com/baeldung/vavr/VavrUnitTest.java b/vavr/src/test/java/com/baeldung/vavr/VavrUnitTest.java index 08a5e20b40..7beb75632e 100644 --- a/vavr/src/test/java/com/baeldung/vavr/VavrUnitTest.java +++ b/vavr/src/test/java/com/baeldung/vavr/VavrUnitTest.java @@ -216,11 +216,11 @@ public class VavrUnitTest { assertEquals(-1, errorSentinel); } - // @Test(expected = ArithmeticException.class) - // public void givenBadCode_whenTryHandles_thenCorrect3() { - // Try result = Try.of(() -> 1 / 0); - // result.getOrElseThrow(ArithmeticException::new); - // } + @Test(expected = RuntimeException.class) + public void givenBadCode_whenTryHandles_thenCorrect3() { + Try result = Try.of(() -> 1 / 0); + result.getOrElseThrow(e->new RuntimeException(e));//re-throw different ex type + } // lazy @Test