I want to find beans at runtime depending on user input, so using io.quarkus.arc.Arc.
However, I cannot figure out how to get beans with custom annotation in a reasonable way. Only got something working by implementing the annotation interface like:
InstanceHandle<Service> instanceHandleA = Arc.container()
.instance(Service.class, new SupportsJobTypeImpl(JobType.A));
InstanceHandle<Service> instanceHandleB = Arc.container()
.instance(Service.class, new SupportsJobTypeImpl(JobType.B));
class SupportsJobTypeImpl implements SupportsJobType {
JobType requestedJobType;
public SupportsJobTypeImpl(JobType requestedJobType) {
this.requestedJobType = requestedJobType;
}
#Override
public JobType value() {
return requestedJobType;
}
#Override
public Class<? extends Annotation> annotationType() {
return SupportsJobType.class;
}
}
Is there a way to get instanceHandleA, instanceHandleB with less cumbersome verbose code like SupportsJobTypeImpl?
Background info about my test code:
public enum JobType {
A,B
}
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface SupportsJobType {
JobType value();
}
#ApplicationScoped
#SupportsJobType(JobType.A)
public class ServiceForA extends Service {
}
#ApplicationScoped
#SupportsJobType(JobType.B)
public class ServiceForB extends Service {
}
UPDATE: Tried to get it working by including SupportsJobTypeImpl in the SupportsJobType annotation interface (like in the example from https://docs.jboss.org/cdi/api/2.0/javax/enterprise/util/AnnotationLiteral.html):
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface SupportsJobType {
JobType value();
public abstract class Literal extends AnnotationLiteral<SupportsJobType> implements SupportsJobType {
JobType requestedJobType;
public Literal() {
}
#Override
public JobType value() {
return requestedJobType;
}
#Override
public Class<? extends Annotation> annotationType() {
return SupportsJobType.class;
}
}
}
however, I get no bean instance from ArC by:
InstanceHandle<Service> instanceHandleA = Arc.container().instance(Service.class, new SupportsJobType.Literal() {
public JobType value() {
return JobType.A;
}
});
UPDATE2: also not working:
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface SupportsJobType {
JobType value();
class Literal extends AnnotationLiteral<SupportsJobType> implements SupportsJobType {
JobType requestedJobType;
public Literal(JobType requestedJobType) {
this.requestedJobType = requestedJobType;
}
#Override
public JobType value() {
return requestedJobType;
}
#Override
public Class<? extends Annotation> annotationType() {
return SupportsJobType.class;
}
}
}
I get no bean instance from ArC by:
InstanceHandle<Service> instanceHandleA = Arc.container().instance(Service.class, new SupportsJobType.Literal(JobType.A));
As far as I can tell, what you're doing is exactly what you should do. It is idiomatic for implementations of annotation types to be nested in the annotation type itself, be called Literal and extend the AnnotationLiteral class. For example (writing from memory):
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface SupportsJobType {
JobType value();
class Literal extends AnnotationLiteral<SupportsJobType> implements SupportsJobType {
private final JobType value;
public Literal(JobType value) {
this.value = value;
}
#Override
public JobType value() {
return value;
}
}
}
Turns out I was stumbling over a small detail like mentioned in https://stackoverflow.com/a/66980506/753724
which means I simply had to add #Unremovable to beans resulting in:
#ApplicationScoped
#Unremovable
#SupportsJobType(JobType.A)
public class ServiceForA extends Service {
}
#ApplicationScoped
#Unremovable
#SupportsJobType(JobType.B)
public class ServiceForB extends Service {
}
With the slightly adapted Annotation class (only new static method):
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface SupportsJobType {
JobType value();
class Literal extends AnnotationLiteral<SupportsJobType> implements SupportsJobType {
JobType requestedJobType;
public Literal(JobType requestedJobType) {
this.requestedJobType = requestedJobType;
}
public static Literal of(JobType value) {
return new Literal(value);
}
#Override
public JobType value() {
return requestedJobType;
}
#Override
public Class<? extends Annotation> annotationType() {
return SupportsJobType.class;
}
}
}
the beans were found as expected by:
InstanceHandle<Service> instanceHandleA = Arc.container().instance(Service.class, SupportsJobType.Literal.of(JobType.A));
InstanceHandle<Service> instanceHandleB = Arc.container().instance(Service.class, SupportsJobType.Literal.of(JobType.B));
Related
Does XStream handle JAXB #XmlTransient attributes by default? XStream seems to be ignoring the #XmlTransient attribute & serializing the field anyway.
In the sample code below. ExampleClass2 is getting serialized even though I don't want it to be. Further details are that these classes are being populated by OpenJPA.
XStream Code
XStream _x0 =null;
_x = XStreamImpl.getInstance();
_x.toXML(_object)
Class I want to serialize
#DataCache
#Entity
public class ExampleClass implements Serializable {
private short defaultOption;
private int primaryKey;
private short orderId;
#XmlTransient
private ExampleClass2 _exampleClass2;
#XmlTransient
public ExampleClass2 getTblPpwsCommCfgCombo() {
return _exampleClass2;
}
#XmlTransient
public void setExampleClass2(ExampleClass2 _exampleClass2) {
this._exampleClass2 = _exampleClass2;
}
public short getDefaultOption() {
return defaultOption;
}
public void setDefaultOption(short defaultOption) {
this.defaultOption = defaultOption;
}
public short getPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(int primaryKey) {
this.primaryKey = primaryKey;
}
public short getOrderId() {
return orderId;
}
public void setOrderId(short orderId) {
this.orderId = orderId;
}
}
You can use the #Transient annotation or transiet key word:
#Transient
private ExampleClass2 _exampleClass2;
~
How to use a generic common Interface for Jax-WS ?
public interface IGenericWebService<T extends Record> {
#WebMethod
public List<T> listAll();
}
how to make it works without overriding the method ?
#WebService
public interface IWCustomerService extends IGenericWebService<Customer>{
/*
#WebMethod
public List<Customer> listAll(); */
}
Common implementation
public abstract class GenericWebService<T extends Record> implements IGenericWebService<T>{
protected static Log log = LogFactory.getLog(GenericWebService.class);
}
Customer Service
#WebService(endpointInterface="com.dev.bridge.iwservices.IWCustomerService")
#Service
public class WCustomerService extends GenericWebService<Customer> implements IWCustomerService{
#Autowired
private ICustomerService customerService;
public List<Customer> listAll() {
try {
return customerService.listAll();
} catch (CoreException e) {
log.error(e.getMessage(), e);
}
return new ArrayList<Customer>();
}
}
I have XML as follows
<request type="1">
<request-header/>
<request-details>
<!-- Some more tags -->
</request-details>
</request>
For mapping this XML I have class structure as follows :
public class Request1
{
private RequestDetail_1;
//other members
}
public class Request2
{
private RequestDetail_2;
//other members
}
public class RequestDetail_1
{
//members
}
public class RequestDetail_2
{
//Members
}
What I want to do is ... If attribute type is 1 then I need to create object of type Request_1 , if type is 2 then object type will be Request_2 and so on.
I have gone through this link for reference but still couldn't figure out a way to do this. I want to use pure JAXB and not MOXY or any other such frame works... :( .
Partial code :
#XmlJavaTypeAdapter(RequestAdaptor.class)
#XmlRootElement(name="request")
public class AuthRequest extends Request
{
private AuthRequestDetails requestDetails;
public RequestDetails getRequestDetails()
{
return requestDetails;
}
#Override
public void setRequestDetails(RequestDetails requestDetails)
{
this.requestDetails = (AuthRequestDetails)requestDetails;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
public class AuthRequestDetails extends RequestDetails
{
#XmlElement(name="user-name")
private String userName;
#XmlElement(name="password")
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlJavaTypeAdapter(RequestAdaptor.class)
public abstract class Request
{
#XmlAttribute
protected String type;
#XmlElement(name="request-header")
protected RequestHeader requestHeader;
public RequestHeader getRequestHeader()
{
return requestHeader;
}
public void setRequestHeader(RequestHeader requestHeader)
{
this.requestHeader = requestHeader;
}
public String getType()
{
return type;
}
public void setType(String type)
{
this.type = type;
}
public abstract void setRequestDetails(RequestDetails requestDetails);
public abstract RequestDetails getRequestDetails();
}
public class RequestAdaptor extends XmlAdapter<RequestDTO, Request>
{
#Override
public RequestDTO marshal(Request v) throws Exception
{
System.out.println("marshal");
RequestDTO lRequestDTO= new RequestDTO();
lRequestDTO.setRequestHeader(v.getRequestHeader());
lRequestDTO.setType(v.getType());
if(v.getType().equals("5"))
{
AuthRequest lRequest = (AuthRequest)v;
}
else
{
PingRequest lRequest = (PingRequest)v;
}
return lRequestDTO;
}
#Override
public Request unmarshal(RequestDTO v) throws Exception
{
System.out.println("unmarshal");
if(v.getType().equals("5"))
{
AuthRequest lRequest = new AuthRequest();
lRequest.setRequestHeader(v.getRequestHeader());
lRequest.setType(v.getType());
return lRequest;
}
else
{
PingRequest lRequest = new PingRequest();
lRequest.setRequestHeader(v.getRequestHeader());
lRequest.setType(v.getType());
return lRequest;
}
}
}
#XmlAccessorType(XmlAccessType.FIELD)
public class RequestDTO
{
#XmlAttribute
protected String type;
#XmlElement(name="request-header")
private RequestHeader requestHeader;
#XmlElement(name="request-details")
private RequestDetails requestDetails;
public RequestHeader getRequestHeader()
{
return requestHeader;
}
public void setRequestHeader(RequestHeader requestHeader)
{
this.requestHeader = requestHeader;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public RequestDetails getRequestDetails() {
return requestDetails;
}
public void setRequestDetails(RequestDetails requestDetails) {
this.requestDetails = requestDetails;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
public class RequestHeader
{
#XmlElement(name="name")
String Name;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
}
First thing is : Marshal and Unmarshal of Adaptor is not getting called. I am stuck at this point.
You can use a StAX XmlStreamReader to parse the XML. Then advance it to the root element. When it's at the root element event check the value of the type attribute. Use this value to determine which Class you should pass to the unmarshal method that takes a Class and XmlStreamReader to get the result you are looking for.
using JAXB 2.2.5b, and having
#XmlSeeAlso({BeanView.class, ViewField.class, ViewPanel.class, ViewTab.class, ElementRef.class})
#XmlRootElement
public abstract class ViewElement {
#XmlID
#XmlAttribute
public String getId() {
return id;
}
}
#XmlRootElement(name="ref")
public class ElementRef extends ViewElement{
private ViewElement target;
#XmlElement
#XmlIDREF
public ViewElement getTarget() {
return target;
}
public void setTarget(ViewElement target) {
this.target = target;
}
}
Many class extends the abstract ViewElement
#XmlRootElement
public class ViewField extends ViewElement{
}
#XmlRootElement
public class ViewPanel extends ViewElement{
}
in the XML the ElementRef target element is repeated instead of keeping only the id ref
<ref id="mvmCredit" >
<target xsi:type="viewField" valueExpr="" row="0" ... all ViewField attributes >
</target>
</ref>
and during the unmarchaling of the XML model the target is null (the restoration failed)
An upgrade to JAXB 2.2.7 fix the problem
Here is what I have so far to marshall my POJO using JAXB :
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlElement
public Entity getEntity() {
return entity;
}
}
and
#XmlRootElement
public class Entity {
private String name;
private String comment;
public void setName(String name){
this.name = name;
}
#XmlAttribute
public String getName(){
return this.name;
}
public void setComment...
#XmlAttribute
public void getComment...
}
With that, I get something like this:
<local>
<entity name="" comment=""></entity>
</local>
However, I would prefer to have the name attribute as an attribute of the local:
<local entityName="" entityComment=""></local>
Is the XmlJavaTypeAdapter a good way to begin with?
Thanks,
Alex
There are a couple of different options to handle this use case:
Option #1 - XmlAdapter (Any JAXB implementation)
You could use an XmlAdapter for this use case. This will work as long as only one attribute value comes from the Entity object:
EntityAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class EntityAdapter extends XmlAdapter<String, Entity>{
#Override
public String marshal(Entity entity) throws Exception {
if(null == entity) {
return null;
}
return entity.getName();
}
#Override
public Entity unmarshal(String name) throws Exception {
Entity entity = new Entity();
entity.setName(name);
return entity;
}
}
Local
The XmlAdapter is linked with the field/property using the #XmlJavaTypeAdapter annotation:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlAttribute
#XmlJavaTypeAdapter(EntityAdapter.class)
public Entity getEntity() {
return entity;
}
}
For More Information
http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html
http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html
Option #2 - #XmlPath (EclipseLink JAXB (MOXy)
Alternatively if you are using EclipseLink JAXB (MOXy), the you could use the #XmlPath extension. This is useful with the Entity object corresponds to multiple XML attributes:
Local
Specifying the XPath "." indicated that the child contents will be written into the parent element
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#XmlRootElement
public class Local {
private Entity entity;
public void setEntity(Entity entity) {
this.entity = entity;
}
#XmlPath(".")
public Entity getEntity() {
return entity;
}
}
Entity
public class Entity {
private String name;
private String comment;
public void setName(String name){
this.name = name;
}
#XmlAttribute(name="entityName")
public String getName(){
return this.name;
}
public void setComment(String comment){
this.comment = comment;
}
#XmlAttribute(name="entityComment")
public String getComment(){
return this.comment;
}
}
For More Information
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html