JAX-WS webservice on tomcat - cannot be instantiated - java

I would like to know how to handle this situation.
what i have done is i have followed the tutorial http://www.mkyong.com/webservices/jax-ws/deploy-jax-ws-web-services-on-tomcat-ssl-connection/
to create a similar secured web service, i am able to achieve it, but i have a error ,
ml.ws.api.server.InstanceResolver.createNewInstance(InstanceResolver.java:222)
at com.sun.xml.ws.api.server.InstanceResolver.createDefault(InstanceResolver.java:184)
at com.sun.xml.ws.server.EndpointFactory.create(EndpointFactory.java:209)
the error is because i am instantiating the webservice for example from this example the HelloWorldImpl class has a constructor with arguments to set a parameter from a class.
I understand , only default constructor is possible in Jax-ws web service, but in that case i want to know how to handle this?
say like
package com.mkyong.ws;
import javax.jws.WebService;
//Service Implementation Bean
#WebService(endpointInterface = "com.mkyong.ws.HelloWorld")
public class HelloWorldImpl implements HelloWorld{
private ABC abc;
public HelloWorldImpl (ABC abc)
{
this.abc = abc;
}
#Override
public String getHelloWorldAsString() {
return "Hello World JAX-WS";
}
// and i use this abc in one of the methods
}

This is not the correct notation for a constructor:
public void HelloWorldImpl (ABC abc) {
this.abc = abc;
}
Should be:
public HelloWorldImpl (ABC abc) {
this.abc = abc;
}
Update: So why not add a default constructor?
package com.mkyong.ws;
import javax.jws.WebService;
//Service Implementation Bean
#WebService(endpointInterface = "com.mkyong.ws.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
private ABC abc;
public HelloWorldImpl() {
this("Hello World JAX-WS");
}
public HelloWorldImpl (ABC abc)
{
this.abc = abc;
}
#Override
public String getHelloWorldAsString() {
return this.getAbc();
}
// and i use this abc in one of the methods
}

I think you can control how the HelloWorldImpl gets created by using: #InstanceResolverAnnotation
I wasn't able to find any good example, but here is one link that uses this annotation: http://blog.vinodsingh.com/2008/12/let-spring-load-service-class-for-jax.html
The idea is that the class specified as the Value for this Annotation, will be used to create the Instance of HelloWorld WebService.

Related

Deserialize enum ignoring case in Spring Boot controller

I have Spring Boot endpoint which has enum as query param:
#GetMapping("/example")
public List<Example> getByEnum(#RequestParam(name = "exampleEnum", required = false) ExampleEnum exampleEnum) {
// code
}
And enum class:
public enum ExampleEnum {
FIRST,
SECOND,
}
If I pass uppercase enum value to the endpoit, it deserializes well but it throws error for lowercase:
java.lang.IllegalArgumentException: No enum constant
How to deserialize enum ignoring case in Spring Boot Rest endpoint?
This question is not duplicate because it's related to query param deserialization.
EDIT: The answer below is incorrect. You have to define a custom PropertyEditor and register it with Spring #InitBinder which I explained in this post. Thanks to #Dave for pointing this out in the comments.
Spring Boot 2.0 is using Jackson 2.9 which has ACCEPT_CASE_INSENSITIVE_ENUMS feature. You should be able to enable it by setting
spring.jackson.mapper.ACCEPT_CASE_INSENSITIVE_ENUMS = true
property as per docs, Appendix A.
import com.fasterxml.jackson.annotation.JsonCreator;
import java.util.Arrays;
import java.util.Optional;
public enum ExampleEnum {
FIRST,
SECOND;
#JsonCreator
public static ExampleEnum setValue(String key) {
return Arrays.stream(ExampleEnum.values())
.filter(exampleEnum -> exampleEnum.toString().equals(key.toUpperCase()))
.findAny()
.orElse(null);
}
You can make generic converter for all enums
package ru.grancall.kb.logging.service.dto.converter;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.EnumUtils;
import java.beans.PropertyEditorSupport;
#AllArgsConstructor
public class EnumConverter extends PropertyEditorSupport {
private Class type;
public void setAsText(String text) {
setValue(EnumUtils.getEnum(type, text.toUpperCase()));
}
}
And then in any of your Controllers use it:
#InitBinder
public void initBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(YourEnum.class, new EnumConverter(YourEnum.class));
}
If you want to get ALL your enums handled case-insensitively you can use Spring's ApplicationConversionService.
You only have to register it with the following little Configuration (see baeldung):
#Configuration
public class EnumMappingConfig implements WebMvcConfigurer {
#Override
public void addFormatters(FormatterRegistry registry) {
ApplicationConversionService.configure(registry);
}
}

AbstractContainerRequestValueFactory removed from Jersey 2.26

I upgrade Jersey in my project to 2.26 version.
My code is:
import org.glassfish.jersey.server.internal.inject.AbstractContainerRequestValueFactory;
public class ClassA extends AbstractContainerRequestValueFactory<ClassB> {
#Override
public ClassB provide() {
.....
}
}
AbstractContainerRequestValueFactory class was removed, and I didn't found how to fix this.
From https://github.com/jersey/jersey/commit/1f4614787c4cfddb5d9177c6c2a663b96ab673cc#diff-bcd9d3f0cfac8ea5e8e9a6b00119237b
commit we can see we should use below code instead.
private static final class BeanParamValueProvider implements Function<ContainerRequest, Object> {
Alternatively, we can use custom HK2 bindings, that are configured as part of Jersey application. Add jersey-hk2 dependency dependency in the classpath org.glassfish.jersey.inject:jersey-hk2
Define the Factory class to generate the instance based on the resource scopes
import org.glassfish.hk2.api.Factory;
import javax.ws.rs.ext.Provider;
#Provider
public class ClassA implements Factory<ClassB> {
#Override
public ClassB provide() {
// construct ClassB instance based on your requirement
//here I am simply returning the object
return new ClassB();
}
#Override
public void dispose(ClassB instance) {/**Noop**/}
}
Registering the custom factory class
For instance, I have to inject ClassB instance for every request then I can register the above factory with the scope of RequestScoped, in such case, for every request ClassA#provide will be called to create the value of ClassB instance that can be retrieved as #Context ClassB classB
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
import org.glassfish.jersey.server.ResourceConfig;
import javax.ws.rs.ext.Provider;
#Provider
class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
register(new AbstractBinder() {
#Override
protected void configure() {
bindFactory(ClassA.class)
.to(ClassB.class)
.in(RequestScoped.class);
}
});
}
}
The following scopes are currently supported by Jersey

Configure Spring Property of Subclass Field with Same Name as Parent's

Suppose I have the following classes:
package wild;
import moco.GeneralMovement;
public class Animal{
protected GeneralMovement movement;
public getMovement (){
return movement;
}
public void setMovement (GeneralMovement movement){
this.movement = movement;
}
}
package sur;
import loco.QuadripedalMovement;
import wild.Animal;
public class Mammal extends Animal{
protected QuadripedalMovement movement;
public QuadripedalMovement getMovement (){
return movement;
}
public void setMovement (QuadripedalMovement movement){
this.movement = movement;
}
public void test(){
super.movement.move();
}
}
package zoo;
import sur.Mammal;
public class Gorilla extends Mammal{
public void doSomething(){
test();
movement.grove();
}
}
package moco;
public class GeneralMovement {
public void move(){
System.out.println("Moving");
}
}
package loco;
import moco.GeneralMovement;
public class QuadripedalMovement extends GeneralMovement{
public void grove(){
System.out.println("Grooving...");
}
}
import zoo.Gorilla;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
private ApplicationContext ctx;
public static void main(String[] args) {
Test test = new Test();
test.doProcess();
}
public void doProcess(){
String cfgFiles[] = {"zoo.xml"};
ctx = new ClassPathXmlApplicationContext(cfgFiles);
Gorilla gorilla = (Gorilla) ctx.getBean("Gorilla");
gorilla.doSomething();
}
}
Then the following XML config:
<bean id="Gorilla" class="zoo.Gorilla">
<property name="movement">
<ref bean="QuadripedalMovement"/>
</property>
</bean>
<bean id="QuadripedalMovement" class="loco.QuadripedalMovement" />
</beans>
The above would give a NullPointerException upon calling doSomething() movement.grove().
Moving
Exception in thread "main" java.lang.NullPointerException
at zoo.Gorilla.doSomething(Gorilla.java:9)
at Test.doProcess(Test.java:64)
at Test.main(Test.java:49)
From what I understood from a little research this has something to do with Java not being capable of overriding fields. The above (please correct me if my understanding is wrong) would actually refer to two(?) different fields.
Why does the above code work when move() is invoked through using super keyword? Does this mean that Spring would assign the created QuadripedalMovement class to the parent field instead of the child's despite the class type being explicitly defined in the bean definition class attribute?
How do I configure spring to assign it to the (Mammal) subclass' field so I can reference it through an instance of Gorilla? I cannot modify the Java code for Animal and Gorilla. I can only modify the Mammal class. My temporary solution is to let Mammal implement InitializingBean and setting the value of movement there.
public void afterPropertiesSet() throws Exception {
this.movement = (QuadripedalMovement) super.movement;
}
But I've only recently began to study Spring (and Java) so I don't know if this is correct (or good practice). Any help would be appreciated.
Note: The above code is the same structure as the code I am currently studying. I cannot provide the original. The version of spring used is 2.5.6

Guice: Using providers to get multiple instances:

I am trying to learn Guice for dependency Injection using Providers to create multiple instances of an object(Example from getting started guide on Guice website). how should I test this? Please advise.
The following is the module:
package testing;
import com.google.inject.AbstractModule;
public class BillingModule extends AbstractModule {
#Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(BillingService.class).to(RealBillingService.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
}
}
The following is the class under test:
package testing;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class RealBillingService implements BillingService {
private Provider<CreditCardProcessor> processorProvider;
private Provider<TransactionLog> transactionLogProvider;
#Inject
public RealBillingService(Provider<CreditCardProcessor> processorProvider,
Provider<TransactionLog> transactionLogProvider) {
this.processorProvider = processorProvider;
this.transactionLogProvider = transactionLogProvider;
}
public void chargeOrder() {
CreditCardProcessor processor = processorProvider.get();
TransactionLog transactionLog = transactionLogProvider.get();
/* use the processor and transaction log here */
processor.toString();
transactionLog.toString();
}
}
The following is the test class with main():
public class test {
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BillingModule());
BillingService billingService = injector.getInstance(BillingService.class);
billingService.chargeOrder();
}
}
Upon running this, I am expecting the output from the following toString methods to show up but am seeing nothing:
processor.toString();
transactionLog.toString();
What am i missing here?
Please advise,
thanks!
This happens because you just call toString without putting the resulting string anywhere (eg the call to System.out.println)
However providers are not intended to be used like that. You should not call Provider.get yourself: instead require the result of the provider, register your provider and let Guice do its job (you can also annotate methods in your modules with #Provides instead of defining provider classes)
By default providers are called each time a new instance of a certain class is required. Instances are not recycled unless you explicitly request it via using scopes (like the builtin Singleton)

Polymorphic EJB client

I am using EJB 3.1 and jersey for a restapi. I would like to have a SuperResource as below, which is then inherited by the actual rest resources as below. The way I have it now, my #EJB object is null. Does anyone know how to fix this?
#Stateless
public class SuperResource {
#EJB
protected GenericDao<DomainObject> dao;
. . .
}
public class MyResource extends SuperResource{
public String doGet(){
return dao.get(...);
}
}
I have tried the whole truth table between #Stateless and #Local, and SuperResource and MyResource. None of the permutations seems to work.
I don't know if that's important, my server is Glassfish 3.1.2
EDIT TO ADD DETAILS:
I didn't think so , but it seems that more detail may be necessary here:
Structure of my application:
#Local
public interface GenericDao<T extends DomainObject> {…}
public interface LoginDao extends GenericDao<Login>{...}
#Stateless
public class GenericDaoImpl<T extends DomainObject> implements GenericDao<T> {…}
#Stateless
public class LoginDaoImpl extends GenericDaoImpl<Login> implements LoginDao {…}
#Entity
public class Login implements java.io.Serializable, DomainObject {…}
What works:
#Stateless
#Path("mypath")
public class MyResource{  
#EJB
private LoginDao dao; 
public String doGet(){
return dao.get(...);
}
}
MyResource has to be an EJB bean as well, by annotating it with #Stateless:
#Stateless
public class MyResource extends SuperResource{
public String doGet(){
return dao.get(...);
}
}
If you only need the injected DAO, you could choose to inject your JAX-RS resource with that DAO using CDI instead. If you resources -becomes- a stateless bean, then this has certain consequences that you need to be aware of (like a transaction that starts for every method, unless you explicitly disable that, etc).
It looks like EJB injection issue. Depending on Server, you need to play around mappedName/name/beanName
What I can confirm is that, the following code works on JBoss 7.1.1.
#Local
public interface HelloWorldLocal {
public String sayHello();
}
#Stateless
public class HelloWorldBean implements HelloWorldLocal {
public String sayHello(){
return "Hello..............................................................................";
}
}
#Remote
public interface BaseRemote {
public String test();
}
#Stateless
public class BaseBean implements BaseRemote{
#EJB
HelloWorldLocal bean;
public String test() {
return "Base Bean";
}
}
#Remote
public interface DerivedRemote {
String test();
}
#Stateful
public class DerivedBean extends BaseBean implements DerivedRemote{
public String test() {
return bean.sayHello();
}
}

Categories