How to enable Eclipse auto-completion in application.yml for custom properties declared by #ConfigurationProperties? - eclipse

I made a simple class with configuration properties for my spring-boot project. Everything work as a charm (spring-boot catches options) except the fact that Eclipse doesn't recognize new properties as valid options in application.yml and highlights them as unknown.
Here is the class:
#Component
#ConfigurationProperties(prefix="server")
public class ServerProperties {
private Integer delay;
private DataAdapter dataAdapter = new DataAdapter();
// setters and getters were cut out for the sake of readability
public static class DataAdapter {
private String baseUrl;
private String targetCode;
// setters and getters
}
}
Autocompletion does not work for those properties:
I added the dependency for Spring Boot Configuration Processor to pom.xml as recommended in Spring.io reference, but it does not work as supposed.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
Tried to switch to application.properties but autocompletion still doesn't work.

Spring boot configuration processor works as an annotation processor during compilation time.
It's necessary to enable annotation processing for the Eclipse project and register the processor:
Go to Project / Properties menu
Open Java Compiler / Annotation Processing. Enable project specific settings and check "Enable annotation processing"
Open Java Compiler / Annotation Processing / Factory Path. Check "Enable project specific settings"
Click "Add variable" button, select "M2_REPO", click "Extend" and find org/springframework/boot/spring-boot-configuration-processor/x.x.x.RELEASE/spring-boot-configuration-processor-x.x.x.RELEASE.jar in the Maven repository, where x.x.x is version of your Spring Boot.
Apply changes
Recompile the project, or just touch and save the class with configuration properties to trigger partial recompilation.

I had the same problem and fixed it by adding this to my pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

Related

Mapstruct is not generating implementation for one of my mapper interfaces. Is there a way to know the reason?

I am using mapstruct to map from/to domain objects to DTO
I have more than 20 mappers that are properly being generated.
One of my mappers is no longer being generated, but compilation is successful.
I use maven and i turned on showWarnings flag in the maven-compiler-plugin configuration, however i see no warnings regarding that specific mapper (I do see warnings for other mappers).
Is there a way to get some information from the annotation processor regarding mappers that are not being generated?
My mapper interface (with name changes):
#Mapper
public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
PersonDTO map(Person entity);
Person map(PersonDTO dto);
}
My Maven configuration:
...
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
<version>1.3.0.Final</version>
</dependency>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
...
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.3.0.Final</version>
</path>
</annotationProcessorPaths>
<showWarnings>true</showWarnings>
</configuration>
</plugin>
You can do basic tracing (verbose mode) in the upcoming version of MapStruct. Checkout the documentation. You can try to use the latest MapStruct master in your project and see if it gives info on why this is not working.
For me it was a dependency issue.
My Projet A, had a dependency to another jar B, which contained the object from my mapper method.
That dependency B had a dependency C offering mapstruct mapper for many of the attribut of the object.
Somehow in my project A i was overriding explicitly the version of dependency C to an older version.
So it means that some of the Obj attribute from current B version where not matching with the older C mapper.
Mapstruct said nothing, just stopped generating the impl.
Not sure if this is very clear ... But check your dependencies.

CQ5 QueryBuilder Reference in Sling Servlet

I am declaring a sling servlet like so
#Component(metatype = false)
#Service(Servlet.class)
#Properties({
#Property(name = "sling.servlet.paths", value = "/bin/foo/bar"),
#Property(name = "sling.servlet.methods", value = "POST") })
public class FooBarServlet extends SlingAllMethodsServlet {
...
}
I override doPost like so
#Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException {
...
}
And I am able to post from a client. Great!
I throw in the following
#Reference
private QueryBuilder queryBuilder;
as per the documentation, a reference to query builder should be injected. But it does not seem to. In the log I see this error
bindQueryBuilder cannot be found (java.lang.VerifyError: ...
And when I try to post to the servlet I get this
javax.jcr.RepositoryException: org.apache.sling.api.resource.PersistenceException: Resource at '/bin/foo/bar' is not modifiable.
And in the OSGi console I see my bundle is installed, and this is what it has to say about my servlet
Service ID 3075 Types: javax.servlet.Servlet
Service PID: com.myproject.FooBarServlet
Component Name: com.myproject.FooBarServlet
Component ID: 5526
Vendor: Adobe
Any suggestions as to what I am doing wrong?
I had been using this tutorial as a reference.
I came across this about the Felix Service Component Runtime (SCR)
and so I implemented the following
protected void activate(ComponentContext context) {
LOGGER.info("activating {}", this.getClass().getName());
}
protected void unbindQueryBuilder(QueryBuilder queryBuilder) {
this.queryBuilder = null;
}
protected void bindQueryBuilder(QueryBuilder queryBuilder) {
this.queryBuilder = queryBuilder;
}
and it worked! So upon closer investigation I learned that these bind/unbind methods are actually supposed to be generated by the maven-scr-plugin, of which I have version 1.6.0
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<id>generate-scr-scrdescriptor</id>
<goals>
<goal>scr</goal>
</goals>
<configuration>
<!-- Private service properties for all services. -->
<properties>
<service.vendor>Adobe</service.vendor>
</properties>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.5.2</version>
</dependency>
</dependencies>
</plugin>
and for the annotations I have 1.4.0
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.4.0</version>
<scope>provided</scope>
</dependency>
so although I am not sure why the bind/unbind methods are not getting generated, I know that they should be, so I generate them manually.
Update
I tried to update the maven-scr-plugin to version 1.20.0, which yielded the following error during mvn build
[ERROR] Project depends on org.apache.felix:org.apache.felix.scr.annotations:jar:1.4.0:provided
[ERROR] Minimum required version is 1.9.0
so... I updated the org.apache.felix.scr.annotations to 1.9.0. And it works! My bind/unbind accessors are generated and all is great. However, I am concerned and do not know if I should use version 1.9.0 of org.apache.felix.scr.annotations because I am marking it as provided in the maven dependency and when I look at the OSGi bundles installed on the cq instance I see the following
Apache Felix Declarative Services (org.apache.felix.scr) : Version 1.6.3.R1409029
For the dependency injection to work, you should declare the member variable as public.
Try changing it to
#Reference
public QueryBuilder queryBuilder;

Eclipse WTP not publishing Maven dependencies

I'm trying to set up a basic hello world project using Eclipse Indigo and a Tomcat server. I created a dynamic project with a simple servlet. Tested the servlet and that worked fine. Then I enabled Maven support and added logback to my pom. I put a logging statement in the servlet's doGet method. When running the servlet, it complains it cannot find any bindings because the logback jars are not being copied into the Eclipse tomcat instance. I expected to find the jars published somewhere in here:
${workspace}\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\
How do I get Eclipse to work with WTP/Maven properly? I also tried installing the m2e-wtp connector with no difference.
Check Deployment Assembly (context menu on project), there must be mapping Maven Dependencies -> WEB-INF/lib.
Coming from an ASP.NET background, I find it shocking how much work it takes to get a webapp running with Eclipse WTP and Maven especially if you are learning on your own. Hopefully this quick start guide will help someone else get up to speed quickly.
There are two ways to get a hello world project working in Eclipse WTP with Maven. You can create a Dynamic web project and then add the Maven nature or you can do the opposite.
Pre-requisites for Eclipse with update sites
"Web, XML, Java EE and OSGi Enterprise Development"
http://download.eclipse.org/releases/indigo
"Maven Integration For Eclipse"
http://download.jboss.org/jbosstools/updates/m2eclipse-wtp/
"Maven Integration for WTP"
http://download.jboss.org/jbosstools/updates/m2eclipse-wtp/
Startup configuration
Install copy of Tomcat 7 from http://tomcat.apache.org/download-70.cgi
Window -> Preferences -> Server -> Runtime Environment
Add Apache Tomcat 7.0 and select local installation directory
Option 1: Create Dynamic Web Project then add Maven Nature
Create new Maven project, select archetype
org.apache.maven.archetypes:maven-archetype-webapp
Change to Java EE perspective.
Create a new source folder, src\main\java. Notice how Eclipse is not smart enough to do this for you and also the ordering of the folders is incorrect.
src\main\java folder is listed after src\main\resources. This can be manually fixed later in the project properties.
Create a new servlet. Notice how Eclipse defaults this file in the wrong folder src\main\resources because the order is wrong. Instead, manually select src\main\java.
Change the URL mapping on the second page of the wizard to /* to make testing easier.
Now our servlet is ready but the dependencies on the servlet api are unbound. A) we can add the servlet api as a dependency to our project or B) we can bind to the Eclipse server config for Apache 7.0.
For option A, add this dependency to the pom:
.
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-api</artifactId>
<version>7.0.${set this}</version>
<scope>provided</scope>
</dependency>
For option B:
Project properties -> Java Build Path -> Libraries -> Add Library -> Server Runtime -> Apache Tomcat 7.0
Right click and run on server:
A blank page should come up in the internal browser like http://localhost:8080/${artifact}
Test of dependency publishing:
Add joda-time to the pom.
Add this line in the servlet created earlier for the doGet method and import the necessary dependencies:
.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("The time is now: " + new DateTime().toString());
}
Reload the test page and the output should now be:
The time is now: 2012-03-03T14:14:29.890-05:00
Now if you want to play with Servlet 3.0 and annotations this is not enabled by default, for what reason I don't know.
First force Maven to use Java 1.6 by adding this to your pom, otherwise each time you update your pom the configuration will revert to Java 1.5.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
Open Project Properties -> Project Facets. Change the Version under "Dynamic Web Module" to 3.0, change java version 1.6
Create a new Servlet with class name AnnotatedServlet in src\main\java and notice how the #WebServlet annotation is auto created.
Option 2: Create Dynamic Web Project then add Maven Nature
Select Tomcat Runtime and Dynamic Module Version 3.0
Create source folder src\main\java
Set default output target\classes
Set context directory src\main\webapp
Check generate web.xml
Create servlet with mapping /* for quick testing
Add an output statement to the doGet method
response.getWriter().println("Another test");
Double click the "Deployment descriptor" and add this attribute to the root web-app element metadata-complete="false"
Right click project and select Run As -> Run On Server
Right click project -> Configure -> Convert To Maven Project
Select packaging as war
Edit pom and set compiler to use java 1.6 and add joda-time dependency:
.
<dependencies>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
Right click on the web project in Project Explorer then choose Maven -> Update Project
I faced a similar problem and although I had configured Deployment Assembly correctly it still didn't work. Then I found that under Window -> Preferences -> My Eclipse -> Java Enterprise Project -> Web Project, under the Deployment tab, the management of Dependent projects was turned off. I changed it to deploy jars of dependent projects to the lib folder and then everything worked like a charm. I could even turn off the Deployment Assembly option.

How to: SLF4J with multiple bindings in a GWT Maven multi-module project?

I have a GWT multi-module Maven project.
Layout:
pom.xml
client-module //client side: contains some base classes. I use JDK's java.util.log so that it logs on Firebug's console
server-module //server side: extends some code from client-module (so it uses JUL) for common behaviour. I use log4j
client-module is shared code.
I want to use SLF4J globally but it seems that I cannot use multiple bindings (multiple bindings per project, single binding per maven module).
I would agree, but I want to use a specific SLF4J binding per maven module.
So in my case would be SLF4J-JDK for client-module and SLF4J-log4j for server-module.
Pieces of relevant code:
pom.xml
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.3</version>
</dependency>
client-module/BaseFoo.java
public abstract class BaseFoo {
private static final Logger logger = LoggerFactory.getLogger(BaseFoo.class.getName());
// ... interesting stuff
}
server-module/Foo.java
public class Foo extends BaseFoo {
private static final Logger logger = LoggerFactory.getLogger(BaseFoo.class.getName());
// ...more interesting stuff
}
I have already tried to configure according to documentation, but it doesn't work.
The problem is that SLF4J needs to be GWT ready.
The error I get:
[ERROR] Line 23: No source code is available for type org.slf4j.Logger; did you forget to inherit a required module?
What it means that GWT compiles the BaseFoo class to Javascript (that's why is it in client-module to run on client side) but fails because the classes/source code in SLF4j are not emulated.
Do you have any workarounds?
Thanks!

JUnit + Maven + Eclipse: Why #BeforeClass does not work?

I am using JUnit 4, Maven 2 and latest Eclipse. Problem is simple: I would like to perform some setup (connecting to a database) before my tests are executed.
I tried #BeforeClass in many different locations but Eclipse and Maven are ignoring this. Any help on accomplishing this initial setup?
Thanks!
public abstract class BaseTestCase extends TestCase {
#BeforeClass
public static void doBeforeClass() throws Exception {
System.out.println("No good #BeforeClass");
// DO THE DATABASE SETUP
}
}
Now the tests extending BaseTestCase:
public class LoginActionTest extends BaseTestCase {
#Test
public void testNothing() {
System.out.println("TEST HERE");
assertEquals(true, true);
}
}
Maven and Eclipse just ignore my #BeforeClass ??? Any other way to perform setup before tests?
Sergio, you were right about extending TestCase causing the problem. If you extend TestCase, JUnit treats your test class as an old (pre JUnit 4 class) and picks org.junit.internal.runners.JUnit38ClassRunner to run it. JUnit38ClassRunner does not know about #BeforeClass annotation. Check out source code of runnerForClass method of AllDefaultPossibilitiesBuilder and runnerForClass method of JUnit3Builder for more details.
Note: This problem is not related to Eclipse or Maven.
I suspect that you are running with JUnit 3. Try renaming your test to something which does not start with "test". If the test is no longer executing, you are using JUnit 3 (which assumes that test methods are methods which starts with "test").
Please post your Eclipse launch config.
I have similar problem and I fixed it by specifying surefile and junit versions explisitly:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.8.1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.8.1</version>
</dependency>
</dependencies>
<configuration>
<parallel>methods</parallel>
<threadCount>10</threadCount>
<excludes>
<exclude>**/*IntegrationTest.java</exclude>
</excludes>
</configuration>
</plugin>
More info is here: http://maven.apache.org/plugins/maven-surefire-plugin/examples/junit.html
It seems junit 3.8.1 version is used transiently through maven-resources-plugin and plexus-container-default. You can print dependency tree by calling mvn dependency:tree. I think there's no other way to make surefire use junit 4.