Merge branch 'eugenp:master' into master

This commit is contained in:
Bhabani Prasad Patel 2021-05-26 16:54:20 +05:30
commit b0464bd691
85 changed files with 1625 additions and 18 deletions

View File

@ -0,0 +1,8 @@
package com.baeldung.exceptions.illegalaccesserror;
public class Class1 {
public void bar() {
System.out.println("SUCCESS");
}
}

View File

@ -0,0 +1,10 @@
package com.baeldung.exceptions.illegalaccesserror;
public class Class2 {
public void foo() {
Class1 c1 = new Class1();
c1.bar();
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.exceptions.illegalaccesserror;
public class IllegalAccessErrorExample {
interface Baeldung {
public default void foobar() {
System.out.println("This is a default method.");
}
}
class Super {
private void foobar() {
System.out.println("SuperClass method foobar");
}
}
class MySubClass extends Super implements Baeldung {
}
}

View File

@ -0,0 +1,20 @@
package com.baeldung.exceptions.illegalaccesserror;
public class IllegalAccessErrorSolved {
interface BaeldungSolved {
public default void foobar() {
System.out.println("This is a default method.");
}
}
class SuperSolved {
public void foobar() {
System.out.println("SuperClass method foobar");
}
}
class MySubClassSolved extends SuperSolved implements BaeldungSolved {
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.exceptions.illegalaccesserror;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class IllegalAccessErrorExampleUnitTest {
@Test()
public void givenInterfaceDefaultMethOverriddenPrivateAccess_whenInvoked_thenIllegalAccessError() {
Assertions.assertThrows(IllegalAccessError.class, () -> {
new IllegalAccessErrorExample().new MySubClass().foobar();
});
}
@Test()
public void givenClass1Class2_whenSameClassDefintion_thenNoIllegalAccessError() {
Assertions.assertDoesNotThrow(() -> {
new Class2().foo();
});
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.exceptions.illegalaccesserror;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class IllegalAccessErrorSolvedUnitTest {
@Test()
public void givenInterfaceDefaultMethOverriddenNonPrivateAccess_whenInvoked_thenNoIllegalAccessError() {
Assertions.assertDoesNotThrow(() -> {
new IllegalAccessErrorSolved().new MySubClassSolved().foobar();
});
}
}

View File

@ -0,0 +1,28 @@
package com.baeldung.deserialization.vulnerabilities;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Method;
public class BadThing implements Serializable {
private static final long serialVersionUID = 0L;
Object looselyDefinedThing;
String methodName;
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject();
try {
Method method = looselyDefinedThing.getClass().getMethod(methodName);
method.invoke(looselyDefinedThing);
} catch (Exception e) {
// handle error...
}
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung.deserialization.vulnerabilities;
import java.io.IOException;
import java.io.Serializable;
public class MyCustomAttackObject implements Serializable {
public static void methodThatTriggersAttack() {
try {
Runtime.getRuntime().exec("echo \"Oh, no! I've been hacked\"");
} catch (IOException e) {
// handle error...
}
}
}

View File

@ -0,0 +1,40 @@
package com.baeldung.deserialization.vulnerabilities;
import org.junit.Test;
import org.junit.jupiter.api.DisplayName;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class BadThingUnitTest {
@Test
@DisplayName("When a BadThing object is deserialized, then code execution in MyCustomAttackObject is run.")
public void givenABadThingObject_whenItsDeserialized_thenExecutionIsRun() throws Exception {
BadThing bt = new BadThing();
bt.looselyDefinedThing = new MyCustomAttackObject();
bt.methodName = "methodThatTriggersAttack";
byte[] serializedObject = serialize(bt);
try (InputStream bis = new ByteArrayInputStream(serializedObject);
ObjectInputStream ois = new ObjectInputStream(bis)) {
ois.readObject(); // malicious code is run
}
}
private static byte[] serialize(Object object) throws Exception {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(object);
oos.flush();
return bos.toByteArray();
}
}
}

View File

@ -57,6 +57,7 @@
<properties>
<assertj.version>3.6.1</assertj.version>
<icu4j.version>61.1</icu4j.version>
<maven.compiler.release>15</maven.compiler.release>
</properties>
</project>

View File

@ -64,4 +64,11 @@ public class MultiLineString {
return new String(Files.readAllBytes(Paths.get("src/main/resources/stephenking.txt")));
}
public String textBlocks() {
return """
Get busy living
or
get busy dying.
--Stephen King""";
}
}

View File

@ -16,6 +16,7 @@ public class MultiLineStringUnitTest {
assertEquals(ms.stringJoin(), ms.stringBuilder());
assertEquals(ms.stringBuilder(), ms.guavaJoiner());
assertEquals(ms.guavaJoiner(), ms.loadFromFile());
assertEquals(ms.loadFromFile(), ms.textBlocks());
}
}

View File

@ -111,7 +111,6 @@
<module>core-java-string-operations</module>
<module>core-java-string-operations-2</module>
<module>core-java-string-operations-3</module>
<module>core-java-strings</module>
<module>core-java-sun</module>
<module>core-java-regex</module>
<module>pre-jpms</module>

View File

@ -73,8 +73,6 @@
</build>
<properties>
<!-- lombok: https://projectlombok.org/changelog.html -->
<lombok.version>1.18.10</lombok.version>
<!-- various -->
<hibernate-jpa-2.1-api.version>1.0.0.Final</hibernate-jpa-2.1-api.version>
<!-- delombok maven plugin -->

View File

@ -0,0 +1,238 @@
<?xml version="1.0" encoding="Cp1252"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>maven-pom-types</artifactId>
<version>1.0-SNAPSHOT</version>
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
</pluginRepository>
</pluginRepositories>
<build>
<sourceDirectory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\src\main\java</sourceDirectory>
<scriptSourceDirectory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\src\main\scripts
</scriptSourceDirectory>
<testSourceDirectory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\src\test\java
</testSourceDirectory>
<outputDirectory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\customTarget\classes
</outputDirectory>
<testOutputDirectory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\customTarget\test-classes
</testOutputDirectory>
<resources>
<resource>
<directory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\src\main\resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\src\test\resources</directory>
</testResource>
</testResources>
<directory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\customTarget</directory>
<finalName>simplestPOM-1.0-SNAPSHOT</finalName>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.5</version>
<executions>
<execution>
<id>default-clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>default-testResources</id>
<phase>process-test-resources</phase>
<goals>
<goal>testResources</goal>
</goals>
</execution>
<execution>
<id>default-resources</id>
<phase>process-resources</phase>
<goals>
<goal>resources</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-jar</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>default-compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>default-testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<executions>
<execution>
<id>default-test</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-install</id>
<phase>install</phase>
<goals>
<goal>install</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>default-deploy</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.3</version>
<executions>
<execution>
<id>default-site</id>
<phase>site</phase>
<goals>
<goal>site</goal>
</goals>
<configuration>
<outputDirectory>
C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\customTarget\site
</outputDirectory>
<reportPlugins>
<reportPlugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
</reportPlugin>
</reportPlugins>
</configuration>
</execution>
<execution>
<id>default-deploy</id>
<phase>site-deploy</phase>
<goals>
<goal>deploy</goal>
</goals>
<configuration>
<outputDirectory>
C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\customTarget\site
</outputDirectory>
<reportPlugins>
<reportPlugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
</reportPlugin>
</reportPlugins>
</configuration>
</execution>
</executions>
<configuration>
<outputDirectory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\customTarget\site
</outputDirectory>
<reportPlugins>
<reportPlugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
</reportPlugin>
</reportPlugins>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<outputDirectory>C:\Users\emicu\Desktop\tutorials\maven-modules\maven-pom-types\customTarget\site
</outputDirectory>
</reporting>
</project>

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements. See the NOTICE file distributed with this work for additional
information regarding copyright ownership. The ASF licenses this file to
you under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of
the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License. -->
<!-- START SNIPPET: superpom -->
<project>
<modelVersion>4.0.0</modelVersion>
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<name>Central Repository</name>
<url>https://repo.maven.apache.org/maven2</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
</pluginRepository>
</pluginRepositories>
<build>
<directory>${project.basedir}/target</directory>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
<finalName>${project.artifactId}-${project.version}</finalName>
<testOutputDirectory>${project.build.directory}/test-classes
</testOutputDirectory>
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
<scriptSourceDirectory>${project.basedir}/src/main/scripts
</scriptSourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/java
</testSourceDirectory>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>${project.basedir}/src/test/resources</directory>
</testResource>
</testResources>
<pluginManagement>
<!-- NOTE: These plugins will be removed from future versions of the super
POM -->
<!-- They are kept for the moment as they are very unlikely to conflict
with lifecycle mappings (MNG-4453) -->
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
</plugin>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<reporting>
<outputDirectory>${project.build.directory}/site</outputDirectory>
</reporting>
<profiles>
<!-- NOTE: The release profile will be removed from future versions of
the super POM -->
<profile>
<id>release-profile</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<inherited>true</inherited>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<inherited>true</inherited>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<updateReleaseInfo>true</updateReleaseInfo>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
<!-- END SNIPPET: superpom -->

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.baeldung</groupId>
<artifactId>maven-pom-types</artifactId>
<version>1.0-SNAPSHOT</version>
</project>

View File

@ -0,0 +1,7 @@
## Maven Printing Plugins
This module contains articles about printing from Maven plugins.
### Relevant Articles
- [How to Display a Message in Maven](https://www.baeldung.com/maven-print-message-during-execution)

1
patterns/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/product-service/

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>patterns</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>enterprise-patterns</artifactId>
<packaging>pom</packaging>
<properties>
<camel.version>3.7.4</camel.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-activemq-starter</artifactId>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-test-spring-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-spring-boot-dependencies</artifactId>
<version>${camel.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,34 @@
# Wire Tap Pattern
The application shows you how to use a Wire Tap to monitor, debug or troubleshoot messages flowing through the system, without permanently consuming them off, or making any changes to the expected message in the output channel.
This example shows how to implement this with a simple Apache Camel application using Spring Boot and Apache ActiveMq.
For convenience, we are using in-memory activeMq.
### Configuring and using the Connection Factory
1. Create CamelContext.
2. Connect to embedded (or remote) ActiveMQ JMS broker.
3. Add JMS queue to CamelContext.
4. Load file orders (xml/csv) from src/data into the JMS queue.
5. Based on the extension of the incoming file message, route to the respective queues.
6. Test that the destination route is working.
7. Audit the received file (order) from the wire tap queue.
### How to run the example:
mvn spring-boot:run
The Wire Tap processor, by default, makes a shallow copy of the Camel Exchange instance. The copy of the exchange is sent to the endpoint specified in the wireTap statement. The body of the wire tapped message contains the same object as that in the original message which means any change to the internal state of that object during the wire tap route may also end up changing the main messages body.
To solve this, we need to create a deep copy of the object before passing it to the wire tap destination. Wire Tap EIP provides us with a mechanism to perform a “deep” copy of the message, by implementing the org.apache.camel.Processor class. This needs to be be called using onPrepare statement right after wireTap.
For more details, check out the AmqApplicationUnitTest.class.
### Relevant Articles:
- [Wire tap (Enterprise Integration Pattern)](https://drafts.baeldung.com/?p=103346&preview=true)
- [Intro to Apache camel](https://www.baeldung.com/apache-camel-intro)

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>wire-tap</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<parent>
<artifactId>enterprise-patterns</artifactId>
<groupId>com.baeldung</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<order name="motor" amount="1" customer="honda"/>

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<order name="motor" amount="1" customer="honda"/>

View File

@ -0,0 +1,70 @@
package com.baeldung;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.jms.JmsComponent;
import org.apache.camel.impl.DefaultCamelContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AmqApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(AmqApplication.class, args);
try (CamelContext context = new DefaultCamelContext()) {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
"vm://localhost?broker.persistent=false");
connectionFactory.setTrustAllPackages(true);
context.addComponent("direct", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory));
addRoute(context);
try (ProducerTemplate template = context.createProducerTemplate()) {
context.start();
MyPayload payload = new MyPayload("One");
template.sendBody("direct:source", payload);
Thread.sleep(10000);
} finally {
context.stop();
}
}
}
private static void addRoute(CamelContext context) throws Exception {
context.addRoutes(newExchangeRoute());
}
static RoutesBuilder traditionalWireTapRoute() {
return new RouteBuilder() {
public void configure() {
from("direct:source").log("Main route: Send '${body}' to tap router").wireTap("direct:tap").delay(1000)
.log("Main route: Add 'two' to '${body}'").bean(MyBean.class, "addTwo").to("direct:destination")
.log("Main route: Output '${body}'");
from("direct:tap").log("Tap Wire route: received '${body}'")
.log("Tap Wire route: Add 'three' to '${body}'").bean(MyBean.class, "addThree")
.log("Tap Wire route: Output '${body}'");
from("direct:destination").log("Output at destination: '${body}'");
}
};
}
static RoutesBuilder newExchangeRoute() throws Exception {
return new RouteBuilder() {
public void configure() throws Exception {
from("direct:source").wireTap("direct:tap").onPrepare(new MyPayloadClonePrepare()).end().delay(1000);
from("direct:tap").bean(MyBean.class, "addThree");
}
};
}
}

View File

@ -0,0 +1,14 @@
package com.baeldung;
public class MyBean {
public MyPayload addTwo(MyPayload body) {
body.setValue(body.getValue() + " and two");
return body;
}
public MyPayload addThree(MyPayload body) {
body.setValue(body.getValue() + " and three");
return body;
}
}

View File

@ -0,0 +1,31 @@
package com.baeldung;
import java.io.Serializable;
public class MyPayload implements Serializable {
private static final long serialVersionUID = 1L;
private String value;
public MyPayload(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String toString() {
return value;
}
public MyPayload deepClone() {
MyPayload myPayload = new MyPayload(value);
return myPayload;
}
}

View File

@ -0,0 +1,15 @@
package com.baeldung;
import java.util.Date;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
public class MyPayloadClonePrepare implements Processor {
public void process(Exchange exchange) throws Exception {
MyPayload myPayload = exchange.getIn().getBody(MyPayload.class);
exchange.getIn().setBody(myPayload.deepClone());
exchange.getIn().setHeader("date", new Date());
}
}

View File

@ -0,0 +1,9 @@
# to keep the JVM running
camel.springboot.main-run-controller = true
#configure the URL of the remote ActiveMQ broker
#camel.component.activemq.broker-url=tcp://localhost:61616
#spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.in-memory=true
spring.activemq.pool.enabled=false

View File

@ -0,0 +1,16 @@
# Root logger option
log4j.rootLogger=INFO, file, console
log4j.logger.com.javarticles=INFO, file
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=javarticles.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d | %p | %F %L | %m%n
# Direct log messages to stdout
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{HH:mm}| %p | %F %L | %m%n

View File

@ -28,6 +28,7 @@
<module>intercepting-filter</module>
<module>solid</module>
<module>clean-architecture</module>
<module>enterprise-patterns</module>
</modules>
<dependencyManagement>

View File

@ -0,0 +1,43 @@
package com.baeldung.jpa.returnmultipleentities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Objects;
@Entity
public class Channel {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String code;
private Long subscriptionId;
public void setCode(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public void setSubscriptionId(Long subscriptionId) {
this.subscriptionId = subscriptionId;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Channel channel = (Channel) o;
return Objects.equals(id, channel.id) && Objects.equals(code, channel.code) && Objects.equals(subscriptionId, channel.subscriptionId);
}
@Override
public int hashCode() {
return Objects.hash(id, code, subscriptionId);
}
}

View File

@ -0,0 +1,23 @@
package com.baeldung.jpa.returnmultipleentities;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import java.util.List;
public class ReportRepository {
private final EntityManagerFactory emf;
public ReportRepository() {
emf = Persistence.createEntityManagerFactory("jpa-h2-return-multiple-entities");
}
public List<Object[]> find(String email) {
EntityManager entityManager = emf.createEntityManager();
Query query = entityManager.createQuery("SELECT c, s, u FROM Channel c, Subscription s, User u WHERE c.subscriptionId = s.id AND s.id = u.subscriptionId AND u.email=:email");
query.setParameter("email", email);
return query.getResultList();
}
}

View File

@ -0,0 +1,41 @@
package com.baeldung.jpa.returnmultipleentities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Objects;
@Entity
public class Subscription {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String code;
public void setCode(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public Long getId() {
return id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Subscription subscription = (Subscription) o;
return Objects.equals(id, subscription.id) && Objects.equals(code, subscription.code);
}
@Override
public int hashCode() {
return Objects.hash(id, code);
}
}

View File

@ -0,0 +1,29 @@
package com.baeldung.jpa.returnmultipleentities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String email;
private Long subscriptionId;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void setSubscriptionId(Long subscriptionId) {
this.subscriptionId = subscriptionId;
}
}

View File

@ -113,4 +113,24 @@
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
</properties>
</persistence-unit>
<persistence-unit name="jpa-h2-return-multiple-entities">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.baeldung.jpa.returnmultipleentities.Channel</class>
<class>com.baeldung.jpa.returnmultipleentities.Subscription</class>
<class>com.baeldung.jpa.returnmultipleentities.User</class>
<class>com.baeldung.jpa.returnmultipleentities.ReportRepository</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.temp.use_jdbc_metadata_defaults" value="false"/>
</properties>
</persistence-unit>
</persistence>

View File

@ -0,0 +1,84 @@
package com.baeldung.jpa.returnmultipleentities;
import org.junit.Before;
import org.junit.Test;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
public class ReturnMultipleEntitiesIntegrationTest {
private static EntityManagerFactory factory;
private static EntityManager entityManager;
private ReportRepository reportRepository;
@Before
public void setup() {
factory = Persistence.createEntityManagerFactory("jpa-h2-return-multiple-entities");
entityManager = factory.createEntityManager();
reportRepository = new ReportRepository();
populateH2DB();
}
@Test
public void whenQueryingForMultipleEntitiesInOneQuery_thenJPAReturnsMultipleEntitiesInCorrectOrder() {
List<Object[]> reportDetails = reportRepository.find("user1@gmail.com");
assertEquals(2, reportDetails.size());
for (Object[] reportDetail : reportDetails) {
assertEquals(3, reportDetail.length);
Channel channel = (Channel) reportDetail[0];
Subscription subscription = (Subscription) reportDetail[1];
User user = (User) reportDetail[2];
assertEquals("single", subscription.getCode());
assertEquals("user1@gmail.com", user.getEmail());
if (!("eurosport".equals(channel.getCode()) || "hbo".equals(channel.getCode()))) {
fail();
}
}
}
private static void populateH2DB() {
entityManager.getTransaction().begin();
Subscription single = new Subscription();
single.setCode("single");
Subscription family = new Subscription();
family.setCode("family");
entityManager.persist(single);
entityManager.persist(family);
Channel bbc = new Channel();
bbc.setCode("bbc");
bbc.setSubscriptionId(family.getId());
Channel eurosport = new Channel();
eurosport.setCode("eurosport");
eurosport.setSubscriptionId(single.getId());
Channel hbo = new Channel();
hbo.setCode("hbo");
hbo.setSubscriptionId(single.getId());
entityManager.persist(bbc);
entityManager.persist(eurosport);
entityManager.persist(hbo);
User user1 = new User();
user1.setEmail("user1@gmail.com");
user1.setSubscriptionId(single.getId());
entityManager.persist(user1);
entityManager.getTransaction().commit();
}
}

View File

@ -1340,6 +1340,7 @@
<module>core-java-modules/core-java-os</module>
<module>core-java-modules/core-java-time-measurements</module>
<module>core-java-modules/multimodulemavenproject</module>
<module>core-java-modules/core-java-strings</module>
</modules>
</profile>
</profiles>
@ -1405,7 +1406,7 @@
<maven-jxr-plugin.version>3.0.0</maven-jxr-plugin.version>
<!-- <maven-pmd-plugin.version>3.9.0</maven-pmd-plugin.version> -->
<maven-pmd-plugin.version>3.13.0</maven-pmd-plugin.version>
<lombok.version>1.16.12</lombok.version>
<lombok.version>1.18.20</lombok.version>
<h2.version>1.4.197</h2.version>
</properties>

View File

@ -60,7 +60,7 @@
</build>
<properties>
<spring-boot-admin-starter-client.version>2.4.0</spring-boot-admin-starter-client.version>
<spring-boot-admin-starter-client.version>2.4.1</spring-boot-admin-starter-client.version>
<spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version>
</properties>

View File

@ -76,8 +76,8 @@
</build>
<properties>
<spring-boot-admin-server.version>2.4.0</spring-boot-admin-server.version>
<spring-boot-admin-starter-client.version>2.4.0</spring-boot-admin-starter-client.version>
<spring-boot-admin-server.version>2.4.1</spring-boot-admin-server.version>
<spring-boot-admin-starter-client.version>2.4.1</spring-boot-admin-starter-client.version>
<spring-boot-admin-server-ui-login.version>1.5.7</spring-boot-admin-server-ui-login.version>
<spring-boot-maven-plugin.version>2.0.4.RELEASE</spring-boot-maven-plugin.version>
</properties>

View File

@ -24,6 +24,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
@ -44,6 +48,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,9 @@
package com.baeldung.annotations.conditional;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWarDeployment;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnWarDeployment
public class AdditionalWebConfiguration {
}

View File

@ -0,0 +1,20 @@
package com.baeldung.annotations.conditional;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.boot.system.JavaVersion;
public class ConditionalUtils {
public static boolean isWindows() {
return SystemUtils.IS_OS_WINDOWS;
}
public static boolean isJava8() {
return JavaVersion.getJavaVersion().equals(JavaVersion.EIGHT);
}
public static boolean isJava9() {
return JavaVersion.getJavaVersion().equals(JavaVersion.NINE);
}
}

View File

@ -0,0 +1,16 @@
package com.baeldung.annotations.conditional;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
@Conditional(IsDevEnvCondition.class)
public class DevEnvLoggingConfiguration {
@Bean
@Conditional(IsDevEnvCondition.class)
LoggingService loggingService() {
return new LoggingService();
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.annotations.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class IsDevEnvCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return "dev".equals(System.getProperty("env"));
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.annotations.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class IsWindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ConditionalUtils.isWindows();
}
}

View File

@ -0,0 +1,13 @@
package com.baeldung.annotations.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class Java8Condition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ConditionalUtils.isJava8();
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.annotations.conditional;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Service;
@Service
@Conditional(Java8Condition.class)
public class Java8DependedService {
}

View File

@ -0,0 +1,16 @@
package com.baeldung.annotations.conditional;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.context.annotation.Conditional;
public class Java8OrJava9 extends AnyNestedCondition {
Java8OrJava9() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@Conditional(Java8Condition.class)
static class Java8 { }
@Conditional(Java9Condition.class)
static class Java9 { }
}

View File

@ -0,0 +1,13 @@
package com.baeldung.annotations.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class Java9Condition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return ConditionalUtils.isJava9();
}
}

View File

@ -0,0 +1,19 @@
package com.baeldung.annotations.conditional;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnJava;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.system.JavaVersion;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Service;
@Service
@Conditional({IsDevEnvCondition.class, IsWindowsCondition.class, Java8Condition.class})
@ConditionalOnProperty(
value = "logging.enabled",
havingValue = "true",
matchIfMissing = true)
@ConditionalOnExpression("${logging.enabled:true} and '${logging.level}'.equals('DEBUG')")
@ConditionalOnJava(JavaVersion.EIGHT)
public class LoggingService {
}

View File

@ -0,0 +1,10 @@
package com.baeldung.annotations.conditional;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.ComponentScan;
@TestConfiguration
@ComponentScan("com.baeldung.annotations.conditional")
public class ConditionalTestConfiguration {
}

View File

@ -0,0 +1,52 @@
package com.baeldung.annotations.conditional;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
public class DevEnvLoggingConfigurationUnitTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();
@Test
public void whenDevEnvEnabled_thenDevEnvLoggingConfigurationAndLoggingServiceShouldBeCreated() {
System.setProperty("env", "dev");
contextRunner
.withUserConfiguration(ConditionalTestConfiguration.class)
.run(context ->
Assertions.assertNotNull(
context.getBean(DevEnvLoggingConfiguration.class)
)
);
contextRunner
.withUserConfiguration(ConditionalTestConfiguration.class)
.run(context ->
Assertions.assertNotNull(
context.getBean(LoggingService.class)
)
);
}
@Test
public void whenDevEnvNotEnabled_thenDevEnvLoggingConfigurationAndLoggingServiceShouldNotBeCreated() {
System.setProperty("env", "not-dev");
contextRunner
.withUserConfiguration(ConditionalTestConfiguration.class)
.run(context ->
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () ->
context.getBean(DevEnvLoggingConfiguration.class)
)
);
contextRunner
.withUserConfiguration(ConditionalTestConfiguration.class)
.run(context ->
Assertions.assertThrows(NoSuchBeanDefinitionException.class, () ->
context.getBean(LoggingService.class)
)
);
}
}

View File

@ -0,0 +1,33 @@
package com.baeldung.annotations.conditional;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.mockito.Mockito;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class IsDevEnvConditionUnitTest {
@Test
public void whenDevEnvEnabled_thenDevEnvConditionShouldPass() {
System.setProperty("env", "dev");
Assertions.assertTrue(
new IsDevEnvCondition().matches(
Mockito.mock(ConditionContext.class), Mockito.mock(AnnotatedTypeMetadata.class)
)
);
}
@Test
public void whenDevEnvNotEnabled_thenDevEnvConditionShouldNotPass() {
System.setProperty("env", "not-dev");
Assertions.assertFalse(
new IsDevEnvCondition().matches(
Mockito.mock(ConditionContext.class), Mockito.mock(AnnotatedTypeMetadata.class)
)
);
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.annotations.conditional;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class IsWindowsConditionUnitTest {
@Test
public void whenOnWindows_thenIsWindowsConditionShouldPass() {
try (MockedStatic<ConditionalUtils> theMock = Mockito.mockStatic(ConditionalUtils.class)) {
theMock.when(ConditionalUtils::isWindows)
.thenReturn(true);
Assertions.assertTrue(
new IsWindowsCondition().matches(
Mockito.mock(ConditionContext.class), Mockito.mock(AnnotatedTypeMetadata.class)
)
);
}
}
@Test
public void whenNotOnWindows_thenIsWindowsConditionShouldNotPass() {
try (MockedStatic<ConditionalUtils> theMock = Mockito.mockStatic(ConditionalUtils.class)) {
theMock.when(ConditionalUtils::isWindows)
.thenReturn(false);
Assertions.assertFalse(
new IsWindowsCondition().matches(
Mockito.mock(ConditionContext.class), Mockito.mock(AnnotatedTypeMetadata.class)
)
);
}
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.annotations.conditional;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class Java8ConditionUnitTest {
@Test
public void whenOnJava8_thenJava8ConditionShouldPass() {
try (MockedStatic<ConditionalUtils> theMock = Mockito.mockStatic(ConditionalUtils.class)) {
theMock.when(ConditionalUtils::isJava8)
.thenReturn(true);
Assertions.assertTrue(
new Java8Condition().matches(
Mockito.mock(ConditionContext.class), Mockito.mock(AnnotatedTypeMetadata.class)
)
);
}
}
@Test
public void whenNotOnJava8_thenJava8ConditionShouldNotPass() {
try (MockedStatic<ConditionalUtils> theMock = Mockito.mockStatic(ConditionalUtils.class)) {
theMock.when(ConditionalUtils::isJava8)
.thenReturn(false);
Assertions.assertFalse(
new Java8Condition().matches(
Mockito.mock(ConditionContext.class), Mockito.mock(AnnotatedTypeMetadata.class)
)
);
}
}
}

View File

@ -0,0 +1,39 @@
package com.baeldung.annotations.conditional;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class Java9ConditionUnitTest {
@Test
public void whenOnJava9_thenJava9ConditionShouldPass() {
try (MockedStatic<ConditionalUtils> theMock = Mockito.mockStatic(ConditionalUtils.class)) {
theMock.when(ConditionalUtils::isJava9)
.thenReturn(true);
Assertions.assertTrue(
new Java9Condition().matches(
Mockito.mock(ConditionContext.class), Mockito.mock(AnnotatedTypeMetadata.class)
)
);
}
}
@Test
public void whenNotOnJava9_thenJava9ConditionShouldNotPass() {
try (MockedStatic<ConditionalUtils> theMock = Mockito.mockStatic(ConditionalUtils.class)) {
theMock.when(ConditionalUtils::isJava9)
.thenReturn(false);
Assertions.assertFalse(
new Java9Condition().matches(
Mockito.mock(ConditionContext.class), Mockito.mock(AnnotatedTypeMetadata.class)
)
);
}
}
}

View File

@ -8,6 +8,8 @@ import java.security.Principal;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.http.HttpServletRequest;
@Controller
public class WebController {
@ -19,6 +21,12 @@ public class WebController {
return "external";
}
@GetMapping("/logout")
public String logout(HttpServletRequest request) throws Exception {
request.logout();
return "redirect:/";
}
@GetMapping(path = "/customers")
public String customers(Principal principal, Model model) {
addCustomers();

View File

@ -27,6 +27,7 @@
</table>
<div id="pagefoot" th:include="layout :: footerFragment">Footer
</div>
<a href="/logout">Logout</a>
</div>
<!-- container -->
</body>

View File

@ -19,6 +19,11 @@
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>

View File

@ -0,0 +1,29 @@
package com.baeldung.aliasfor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping
public @interface MyMapping {
@AliasFor(annotation = RequestMapping.class, attribute = "method")
RequestMethod[] action() default {};
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] value() default {};
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] mapping() default {};
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String[] route() default {};
}

View File

@ -0,0 +1,13 @@
package com.baeldung.aliasfor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class MyMappingController {
@MyMapping(action = RequestMethod.PATCH, route = "/test")
public void mappingMethod() {
}
}

View File

@ -0,0 +1,61 @@
package com.baeldung.aliasfor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
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.context.SpringBootTest;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyMappingController.class)
public class AliasForUnitTest {
@Autowired
private ConfigurableApplicationContext context;
Class controllerClass;
@Before
public void setControllerBean() {
MyMappingController controllerBean = context.getBean(MyMappingController.class);
controllerClass = controllerBean.getClass();
}
@Test
public void givenComposedAnnotation_whenExplicitAlias_thenMetaAnnotationAttributeOverridden() {
for (Method method : controllerClass.getMethods()) {
if (method.isAnnotationPresent(MyMapping.class)) {
MyMapping annotation = AnnotationUtils.findAnnotation(method, MyMapping.class);
RequestMapping metaAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
assertEquals(RequestMethod.PATCH, annotation.action()[0]);
assertEquals(0, metaAnnotation.method().length);
}
}
}
@Test
public void givenComposedAnnotation_whenImplictAlias_thenAttributesEqual() {
for (Method method : controllerClass.getMethods()) {
if (method.isAnnotationPresent(MyMapping.class)) {
MyMapping annotationOnBean = AnnotationUtils.findAnnotation(method, MyMapping.class);
assertEquals(annotationOnBean.mapping()[0], annotationOnBean.route()[0]);
assertEquals(annotationOnBean.value()[0], annotationOnBean.route()[0]);
}
}
}
}

View File

@ -249,7 +249,7 @@
<!-- testing -->
<rest-assured.version>2.9.0</rest-assured.version>
<!-- swagger -->
<springfox-swagger.version>2.9.2</springfox-swagger.version>
<springfox-swagger.version>3.0.0</springfox-swagger.version>
<!-- Maven plugins -->
<cargo-maven2-plugin.version>1.6.1</cargo-maven2-plugin.version>
</properties>

View File

@ -6,12 +6,11 @@ import java.util.Collections;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.http.HttpMethod;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.builders.ResponseBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
@ -30,13 +29,12 @@ public class SwaggerConfig {
.build()
.apiInfo(apiInfo())
.useDefaultResponseMessages(false)
.globalResponseMessage(RequestMethod.GET, newArrayList(new ResponseMessageBuilder().code(500)
.message("500 message")
.responseModel(new ModelRef("Error"))
.build(),
new ResponseMessageBuilder().code(403)
.message("Forbidden!!!!!")
.build()));
.globalResponses(HttpMethod.GET, newArrayList(
new ResponseBuilder().code("500")
.description("500 message").build(),
new ResponseBuilder().code("403")
.description("Forbidden!!!!!").build()
));
}
private ApiInfo apiInfo() {