Spring MVC 4 REST with protocol buffers not working - spring

I am trying to use Spring MVC 4's Rest templates to support google protocol buffers as message format. I have am following this post on Spring framework blog
spring-mvc-google-protocol-buffers
I checked out the sourceCode trying to implement it in my environment.
I have two issues- I cannot get it to compile when I turn Java.version to 1.6 and i cannot get it to work as a webapp (don't know what
will be the context-root of the converted war file)
-Details-
I have a requirement to make this code work as a web-app and deploy on java6 container (weblogic 10.3.6 -servlet 2.5 compliant)
So i changed the java 8 features from the codebase to make it Java 6 compatible.
The only problem is when I change the pom.xml's following section
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<start-class>demo.DemoApplication</start-class>
<java.version>1.8</java.version>
</properties>
to change the java.version to 1.6 value, then try to do mvn clean install , the DemoApplicationTests class fails to compile with this error.
-google-protocol-buffers-master\src\test\java\demo\DemoApplicationTests.java:28: cannot find symbol
[ERROR] symbol : constructor RestTemplate(java.util.List<org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter>) is not defined
[ERROR] location: class org.springframework.web.client.RestTemplate
The following link shows that Spring codebase normally doesn't have any Java 8 specific source code so not sure why this code only compiles in Java 8
https://spring.io/blog/2015/04/03/how-spring-achieves-compatibility-with-java-6-7-and-8
--------------------------------------------------------------------------------
The following link shows how to convert a spring boot application to a WAR app.
I did change the pom.xml packaging option to war.
The code gets build by mvn clean install without issues and the .war file gets generated.
But there's no web.xml - so i cannot tell what will be the context-root of the deployed web app.
I either way deployed the webapp on weblogic 10.3.6 ( which is java 6 compatible)
and it deployed fine.
But when I run the DemoApplicationTests (that I have changed to point straight to the URL
using this call (got the context-root from the weblogic console by clicking on the deployed web app)
ResponseEntity<CustomerProtos.Customer> customer = restTemplate.getForEntity(
"http://127.0.0.1:7001/demo-0.0.1-SNAPSHOT/customers/2", CustomerProtos.Customer.class);
I keep getting 404 not found error.
I have put up my changed code here.
https://github.com/robinbajaj123/spring-and-google-protocol-buffers
Your feedback will be appreciated.

You'd need to convert the Spring Boot app to also be a valid Servlet application. If you were using Servlet 3 or later and chose a .war-based deployment from start.spring.io you'd get a ServletIntializer which is a Java class that is the programmatic equivalent of web.xml. Since you're using 2.5, not 3.0, you need an explicit web.xml. You might check out this sample on how to get a Boot app hoisted up in a Servlet 2.5 environment, though using Servlet 2.5 is not recommended!. It's worth mentioning that Servlet 3.0 support was introduced in 2009..
Finally, this code uses Java 8 lambdas. You'll need to replace the lambdas with Java 6-equivalent code. One example I see is:
#Bean
CustomerRepository customerRepository() {
...
The last line in the #Bean definition returns a lambda: customers::get. Replace it with:
final Map<Integer, CustomerProtos.Customer> customers =
new ConcurrentHashMap<Integer, CustomerProtos.Customer>();
return new CustomerRepository() {
public CustomerProtos.Customer findById(int id) {
return customers.get( id) ;
}
};
Similarly, replace the forEach method in the List w/ an old-school for-in loop:
for (CustomerProtos.Customer c : Arrays.asList( ... )) {
customers.put(c.getId(), c);
}

Related

Spring boot, tomcat, rest api 404

I am using Kotlin + Gradle and trying to build a war file to deploy on Tomcat. My application is from the https://start.spring.io plus a simple controller and build the war file using ./gradlew bootWar
#SpringBootApplication
class ServletInitializer : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
return application.sources(DemoApplication::class.java)
}
}
#RestController
class TomcatController {
#GetMapping("/hello")
fun sayHello(): Collection<String> {
return IntStream.range(0, 10)
.mapToObj { i: Int -> "Hello number $i" }
.collect(Collectors.toList())
}
}
when I try to access it I get
Type Status Report
Message The requested resource [/demo-0.0.1-SNAPSHOT/hello] is not available
Description The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
I am super stuck. What am I doing wrong? If I add a html file to the src/main/webapp/index.html it shows up for some reason only the rest api can't be reached.
Spring Boot applications come with a built in Servlet. You are probably already using this feature when launching the application inside your IDE.
This basically means that you can just run your .jar file on any web server and it will be ready to go without setting up an extra tomcat instance.
However, if you want to build a Spring Boot application as a war file and deploy it to an external tomcat, you need to follow some extra steps as explained in this article.
Assuming from what you posted so far: the path that is returned shows another route before your actual controller route "/demo-0.0.1-SNAPSHOT/hello" is this "/demo-0.0.1-SNAPSHOT" the path that your application runs on ? If not it should be included in your controller (assuming you havent set it elsewhere for e.g. in your application.properties).
for e.g. http://localhost:8080/ would be the basepath and either http://localhost:8080/demo-0.0.1-SNAPSHOT/hello or http://localhost:8080/hello would point to your controller. Also your startup logs (for Tomcat and Spring) might give away more about the issue.

WebSocket cannot connect to endpoint when running Spring-Boot 2.2 with lazy bean initialization?

I'm having trouble getting the client to connect to a WebSocket endpoint when the Spring-Boot 2.2 application is started in lazy-init mode.
I was able to get this Spring.io tutorial to work. It uses spring-boot-starter-parent version 2.1.6. I changed the pom.xml to use spring-boot-starter-parent version 2.2.0 and got it to work also.
But when I set spring.main.lazy-initialization=true in application.properties, the client does not connect to the server via WebSocket anymore when I click on the "Connect" button. In Chrome Developer Tool > Network > WebSocket, I see that the client sends a CONNECT request, but it never receives a "CONNECTED" response.
I've uploaded my project file to GitHub here:
https://github.com/hirokiterashima/spring-boot-stomp-messaging-websocket. The first commit is the 'complete' directory of the original project in the Spring.io tutorial, which uses Spring-Boot 2.1.6: https://github.com/spring-guides/gs-messaging-stomp-websocket/tree/master/complete. The second commit contains my changes to pom.xml to use Spring-Boot 2.2.0 and addition of application.properties file to enable lazy initialization. As you can see, all I did in the second commit was change to Spring Boot 2.2.0, updated the jQuery webjars dependency, and enabled lazy initialization. If you comment-out the spring.main.lazy-initialization line in application.properties, it will work.
Did anybody else come across a similar issue? What can I do to make this work?
Thanks for your help!
just register the following #Bean:
#Bean
public LazyInitializationExcludeFilter stompWebSocketHandlerMappingLazyInitializationExcludeFilter() {
return LazyInitializationExcludeFilter.forBeanTypes(HandlerMapping.class);
}
or
#Bean
public LazyInitializationExcludeFilter stompWebSocketHandlerMappingLazyInitializationExcludeFilter() {
return ((beanName, beanDefinition, beanType) -> beanName.equals("stompWebSocketHandlerMapping"));
}

Websphere 8.5 with Spring-5

Is Websphere 8.5.5 compatible with Spring 5? The Validation API referenced in spring5 (validation-api 5) is resulting in MethodNotFound exception.. Any pointers/patch available to get this solved - short of upgrading to Websphere 9?
Caused by: java.lang.NoSuchMethodError:
javax/validation/Configuration.getDefaultParameterNameProvider()Ljavax/validation/ParameterNameProvider;
(loaded from
file:/opt/IBM/WebSphere/AppServer/plugins/javax.j2ee.validation.jar by
org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader#25d460de)
called from class
org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
(loaded from file:../spring-context-5.0.2.RELEASE.jar by
com.ibm.ws.classloader.CompoundClassLoader#1c7dbdd9
The method javax/validation/Configuration.getDefaultParameterNameProvider was added in Bean Validation 1.1, so that indicates the Spring Validator you are using is attempting to use the Bean Validation 1.1 API. According to https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.html:
As of Spring 5.0, this class requires Bean Validation 1.1+
WebSphere 8.5.5 provides Bean Validation 1.0 and did not add support for Bean Validation 1.1 until version 9.0. So, you'll either need to use Spring 4.x or WebSphere 9.x.
The above answer is not correct. You can run Spring 5 in WebSphere 8.5. This may not be the perfect solution for your situation, but this will get you on the correct path.
1.) Provide your Bean Validation 1.1 JAR
Here is a sample of the Maven dependency.
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
2.) Add the following a deployment.xml file to the following location in your EAR file.
/myAppEAR/META-INF/ibmconfig/cells/defaultCell/applications/defaultApp/deployments/defaultApp/deployment.xml
3.) In the contents of your deployment.xml file, you must set the classloaderMode to PARENT_LAST. You must also modify this code to use the correct WAR file name.
Here is a sample...
<appdeployment:Deployment xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:appdeployment="http://www.ibm.com/websphere/appserver/schemas/5.0/appdeployment.xmi" xmi:id="Deployment_1422578178899">
<deployedObject xmi:type="appdeployment:ApplicationDeployment" xmi:id="ApplicationDeployment_1422578178899" startingWeight="10" warClassLoaderPolicy="SINGLE">
<modules xmi:type="appdeployment:WebModuleDeployment" xmi:id="WebModuleDeployment_1422578178899" startingWeight="10000" **uri="myApp.war"** **classloaderMode="PARENT_LAST"**/>
<classloader xmi:id="Classloader_1422578178899" **mode="PARENT_LAST"**/>
</classloader>
</deployedObject>
</appdeployment:Deployment>
#rob-breidecker is correct, this is possible even though WebSphere 8.5.5 provides Bean Validation 1.0. To do this, you need to change the classloader of your application.
To do that via the UI, go to Applications -> WebSphere enterprise applications -> Your Application -> Class loading and update detection and change the Class loader order to be Classes loaded with local class loader first (parent last). This "causes the class loader to attempt to load classes from its local class path before delegating the class loading to its parent.".
If you are deploying an EAR and want this change to propagate to inner applications, you can either change WAR class loader policy to Single class loader for application or change the class loader of the individual war (in the EAR click Manage Modules -> Your Module then change Class loader order).
As long as you provide a version of validation-api (I used 2.0.1.Final), you should get passed the above issue.
The following wasadmin.sh script will apply the above settings (replace app_name with the name of your application): (credit)
dep = AdminConfig.getid('/Deployment:app_name/');
depObject = AdminConfig.showAttribute(dep, 'deployedObject');
AdminConfig.modify(depObject, [['warClassLoaderPolicy', 'SINGLE']]);
classldr = AdminConfig.showAttribute(depObject, 'classloader');
AdminConfig.modify(classldr, [['mode', 'PARENT_LAST']]);
I though at some point it was impossible to do this, but finally, I found a solution, you can use spring 5.X and Boot 2.X with WebShpre 8.5 using the below Steps, just make sure that you project is compatible with:
1- Bean Validation
2- Servelt 3.1
Steps:
1- Create a custom folder on you server for example /opt/custom/lib/spring5 and upload below jars to this folder
a. jakarta.el-3.0.4.jar
b. jakarta.validation-api-2.0.2.jar
2- Create a new shared library in WebSphere as below
a. Go to environment -> shared library
b. Chose the scope to node and server
c. Click on New and fill the value with below
i. Name: spring5
ii. Class path: /opt/custom/lib/spring5
iii. Enable checkbox “use an isolated class loader for this shared library”
3- Restart the server
4- Go to Enterprise Application Click on the application (WAR/EAR)
5- Go To shared library reference add assign it to you application (WAR/EAR)
6- Go to Enterprise Application Click on the application (WAR/EAR)
7- Choose Classes loaded with local class loader first (parent last)
8- Restart the server
In case someone still needs a solution, the only way it worked for me was to change the file https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.html
from 5.x to use the logic from 4.x

filter-name element is missing in generated web.xml

One of our old applications uses Struts-1.2 and EJB-2, generated with xdoclet 1.2.3. Maven 1 is used to build the application using java 1.4. The application has been running in weblogic 8.1 without any issues.
Now we are upgrading to Weblogic 10.3.6 which runs on java 6. When the application is deployed to Weblogic 10.3.6 we encounter the following error.
The error is weblogic.descriptor.DescriptorException: VALIDATION PROBLEMS WERE FOUND problem:
cvc-minLength-valid.1.1: string length (0) is less than minLength facet (1) for filter-nameType
in namespace http://java.sun.com/xml/ns/javaee:<null>
I understand this error is because the web.xml file is missing the filter-name element for a Filter class.
The problem is web.xml is generated by the application as part of the build process and I have no idea where or how to add the filter-name element value. What should I do to get the filter-name element to be added to the generated web.xml?
(Note: There is no problem when deployed to Weblogic8.1. This happens only when trying to deploy on weblogic10.3.6.)
Any help will be much appreciated.
Thanks.
Got it going.
I had to add the following annotation to the filter class...
#web.filter name="FilterClassName"
web.xml generated the filter-name element after I added the above annotation.

How to use Spring Roo with Apache Wicket?

I have a persistence layer (JPA entity objects) created and managed by Roo. It is in its own project, builds to a jar, and I have used it with a separate Spring MVC 3 web application.
I'd like to use this same Roo persistence project in another web application powered by Apache Wicket. I have seen a couple of the Roo add-ons made for Wicket, but none of them even compile (I'm not the only one to have the issue).
The problem I am encountering is that whenever I try to call one of my Roo entities from within a Wicket Page or component, I get the following exception:
Caused by: java.lang.IllegalStateException: Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)
at com.x.domain.UserAccount_Roo_Entity.ajc$interMethod$com_x_domain_UserAccount_Roo_Entity$com_x_domain_UserAccount$entityManager(UserAccount_Roo_Entity.aj:91)
at com.x.domain.UserAccount.entityManager(UserAccount.java:1)
I have configured my application following the Spring+Wicket wiki here: https://cwiki.apache.org/WICKET/spring.html
Does anyone know the 1,2,3 steps to set up a Wicket application to utilize Spring Roo entities? Any help is appreciated. Thanks!
I found this in google code, sounds like its doing exactly what you want http://code.google.com/p/spring-roo-wicket-addon/
I found the solution to my problem. When I ran my wicket webapp using the Maven jetty:run goal, it worked. However, I was trying to start Jetty via Java code:
public class Start {
public static void main(String[] args) throws Exception {
Server server = new Server();
SocketConnector connector = new SocketConnector();
server.start();
}
}
I was not loading the Spring ApplicationContext in this "Start" class. Once I modified this class to load the Spring application context, it worked

Resources