I have tried to generate java classes from a schema xsd with JAXB2.1 and run XJC and it works.
I have included the schema in a wsdl file and i generate java classes with wsdl2java command using CXF.
The problem is abouta java class where there are difference:
The difference is the content attribute and its getter and setter which is missing with wsdl2java command.
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.1-b02-fcs
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
//
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "BIN", **propOrder = {
"content"**
})
#XmlSeeAlso({
ED.class
})
public abstract class BIN {
**#XmlValue
protected String content;**
#XmlAttribute
protected BinaryDataEncoding representation;
/**
public String getContent() {
return content;
}
/**
*
* Binary data is a raw block of bits. Binary data is a
* protected type that MUST not be used outside the data
* type specification.
*
*
* #param value
* allowed object is
* {#link String }
*
*/
**public void setContent(String value) {
this.content = value;
}**
/**
* Gets the value of the representation property.
*
* #return
* possible object is
* {#link BinaryDataEncoding }
*
*/
public BinaryDataEncoding getRepresentation() {
if (representation == null) {
return BinaryDataEncoding.TXT;
} else {
return representation;
}
}
/**
* Sets the value of the representation property.
*
* #param value
* allowed object is
* {#link BinaryDataEncoding }
*
*/
public void setRepresentation(BinaryDataEncoding value) {
this.representation = value;
}
}
I need this attribute into this class.
Is there a way to do this like add a parameter?
This is my wsdl2java command:
call wsdl2java -Debug -verbose -exsh true -autoNameResolution -p %PACKAGE_BASE%.pa -p "urn:hl7-org:v3"=%PACKAGE_BASE%.patient.hl -d %PROJECT_HOME%\src\main\java\ %WSDL_HOME%\Test.wsdl
thanks
Related
I want to create custom CronJob. I followed this tutorial, but unfortunately, I am not able to see my job instance in Backoffice.
*-item.xml
<typegroup name="Jobs">
<itemtype
generate="true"
code="UsersFindCronJob"
extends="CronJob"
jaloclass="de.hybris.training.core.jalo.UsersFindCronJob"
autocreate="true">
<attributes>
<attribute qualifier="firstName" type="java.lang.String">
<modifiers/>
<persistence type="property"/>
</attribute>
</attributes>
</itemtype>
</typegroup>
*spring.xml
<bean id="usersFindJob" class="de.hybris.training.core.job.UsersFindJob"
parent="abstractJobPerformable"/>
UsersFindJob.java
package de.hybris.training.core.job;
import de.hybris.platform.cronjob.enums.CronJobResult;
import de.hybris.platform.cronjob.enums.CronJobStatus;
import de.hybris.platform.servicelayer.cronjob.AbstractJobPerformable;
import de.hybris.platform.servicelayer.cronjob.PerformResult;
import de.hybris.training.core.model.UsersFindCronJobModel;
public class UsersFindJob extends AbstractJobPerformable<UsersFindCronJobModel> {
#Override
public PerformResult perform(UsersFindCronJobModel cronJobModel) {
try {
// Retrieve firstName from the cronJob
String firstName = cronJobModel.getFirstName();
// Display Hello firstName
System.out.println("Hello " + firstName);
// In case of success return result: SUCCESS and status: FINISHED
return new PerformResult(CronJobResult.SUCCESS, CronJobStatus.FINISHED);
} catch(Exception e) {
// In case of exception return result: ERROR and status: ABORTED
return new PerformResult(CronJobResult.ERROR, CronJobStatus.ABORTED);
}
}
}
Autogenerated UsersFindCronJobModel
/*
* ----------------------------------------------------------------
* --- WARNING: THIS FILE IS GENERATED AND WILL BE OVERWRITTEN! ---
* --- Generated at 09.Nis.2018 22:52:22 ---
* ----------------------------------------------------------------
*
* [y] hybris Platform
*
* Copyright (c) 2000-2016 SAP SE
* All rights reserved.
*
* This software is the confidential and proprietary information of SAP
* Hybris ("Confidential Information"). You shall not disclose such
* Confidential Information and shall use it only in accordance with the
* terms of the license agreement you entered into with SAP Hybris.
*
*/
package de.hybris.training.core.model;
import de.hybris.bootstrap.annotations.Accessor;
import de.hybris.platform.core.model.ItemModel;
import de.hybris.platform.cronjob.model.CronJobModel;
import de.hybris.platform.cronjob.model.JobModel;
import de.hybris.platform.servicelayer.model.ItemModelContext;
/**
* Generated model class for type UsersFindCronJob first defined at extension trainingcore.
*/
#SuppressWarnings("all")
public class UsersFindCronJobModel extends CronJobModel
{
/**<i>Generated model type code constant.</i>*/
public static final String _TYPECODE = "UsersFindCronJob";
/** <i>Generated constant</i> - Attribute key of <code>UsersFindCronJob.firstName</code> attribute defined at extension <code>trainingcore</code>. */
public static final String FIRSTNAME = "firstName";
/**
* <i>Generated constructor</i> - Default constructor for generic creation.
*/
public UsersFindCronJobModel()
{
super();
}
/**
* <i>Generated constructor</i> - Default constructor for creation with existing context
* #param ctx the model context to be injected, must not be null
*/
public UsersFindCronJobModel(final ItemModelContext ctx)
{
super(ctx);
}
/**
* <i>Generated constructor</i> - Constructor with all mandatory attributes.
* #deprecated since 4.1.1 Please use the default constructor without parameters
* #param _job initial attribute declared by type <code>CronJob</code> at extension <code>processing</code>
*/
#Deprecated
public UsersFindCronJobModel(final JobModel _job)
{
super();
setJob(_job);
}
/**
* <i>Generated constructor</i> - for all mandatory and initial attributes.
* #deprecated since 4.1.1 Please use the default constructor without parameters
* #param _job initial attribute declared by type <code>CronJob</code> at extension <code>processing</code>
* #param _owner initial attribute declared by type <code>Item</code> at extension <code>core</code>
*/
#Deprecated
public UsersFindCronJobModel(final JobModel _job, final ItemModel _owner)
{
super();
setJob(_job);
setOwner(_owner);
}
/**
* <i>Generated method</i> - Getter of the <code>UsersFindCronJob.firstName</code> attribute defined at extension <code>trainingcore</code>.
* #return the firstName
*/
#Accessor(qualifier = "firstName", type = Accessor.Type.GETTER)
public String getFirstName()
{
return getPersistenceContext().getPropertyValue(FIRSTNAME);
}
/**
* <i>Generated method</i> - Setter of <code>UsersFindCronJob.firstName</code> attribute defined at extension <code>trainingcore</code>.
*
* #param value the firstName
*/
#Accessor(qualifier = "firstName", type = Accessor.Type.SETTER)
public void setFirstName(final String value)
{
getPersistenceContext().setPropertyValue(FIRSTNAME, value);
}
}
Autogenerated GeneratedUsersFindCronJob
/*
* ----------------------------------------------------------------
* --- WARNING: THIS FILE IS GENERATED AND WILL BE OVERWRITTEN! ---
* --- Generated at 09.Nis.2018 22:52:22 ---
* ----------------------------------------------------------------
*
* [y] hybris Platform
*
* Copyright (c) 2000-2016 SAP SE
* All rights reserved.
*
* This software is the confidential and proprietary information of SAP
* Hybris ("Confidential Information"). You shall not disclose such
* Confidential Information and shall use it only in accordance with the
* terms of the license agreement you entered into with SAP Hybris.
*
*/
package de.hybris.training.core.jalo;
import de.hybris.platform.cronjob.jalo.CronJob;
import de.hybris.platform.jalo.Item.AttributeMode;
import de.hybris.platform.jalo.SessionContext;
import de.hybris.training.core.constants.TrainingCoreConstants;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Generated class for type {#link de.hybris.training.core.jalo.UsersFindCronJob UsersFindCronJob}.
*/
#SuppressWarnings({"deprecation","unused","cast","PMD"})
public abstract class GeneratedUsersFindCronJob extends CronJob
{
/** Qualifier of the <code>UsersFindCronJob.firstName</code> attribute **/
public static final String FIRSTNAME = "firstName";
protected static final Map<String, AttributeMode> DEFAULT_INITIAL_ATTRIBUTES;
static
{
final Map<String, AttributeMode> tmp = new HashMap<String, AttributeMode>(CronJob.DEFAULT_INITIAL_ATTRIBUTES);
tmp.put(FIRSTNAME, AttributeMode.INITIAL);
DEFAULT_INITIAL_ATTRIBUTES = Collections.unmodifiableMap(tmp);
}
#Override
protected Map<String, AttributeMode> getDefaultAttributeModes()
{
return DEFAULT_INITIAL_ATTRIBUTES;
}
/**
* <i>Generated method</i> - Getter of the <code>UsersFindCronJob.firstName</code> attribute.
* #return the firstName
*/
public String getFirstName(final SessionContext ctx)
{
return (String)getProperty( ctx, FIRSTNAME);
}
/**
* <i>Generated method</i> - Getter of the <code>UsersFindCronJob.firstName</code> attribute.
* #return the firstName
*/
public String getFirstName()
{
return getFirstName( getSession().getSessionContext() );
}
/**
* <i>Generated method</i> - Setter of the <code>UsersFindCronJob.firstName</code> attribute.
* #param value the firstName
*/
public void setFirstName(final SessionContext ctx, final String value)
{
setProperty(ctx, FIRSTNAME,value);
}
/**
* <i>Generated method</i> - Setter of the <code>UsersFindCronJob.firstName</code> attribute.
* #param value the firstName
*/
public void setFirstName(final String value)
{
setFirstName( getSession().getSessionContext(), value );
}
}
Impex
INSERT_UPDATE UsersFindCronJob ; code[unique=true] ; job(code) ; firstName ; usersFindCronJob ; usersFindJob ; Mouad
I also tried to import that Impex but it said it is not valid.
I think you only missed to update your system. Then you can create the instance of your job using below Impex or through Backoffice.
To update
ant clean all
hybrisserver.bat
Open HAC (https://localhost:9002/hac/)
Go to Platform > Update
Only select Update running system checkbox and essential data of your extension.
If you are in the situation where you can't run essential data(say Production) you need to explicitly run ServiceLayerJob after the update.
Click on update button
Run Impex
INSERT_UPDATE UsersFindCronJob ; code[unique=true] ; job(code) ; firstName ;
; usersFindCronJob ; usersFindJob ; Mouad ;
The situation where you haven't run essential data you need to run below Impex(as mentioned by #Johannes)
INSERT_UPDATE ServicelayerJob;code[unique=true];springId;
;usersFindJob;usersFindJob
Refer https://wiki.hybris.com/display/R5T/Trail+~+CronJobs
First, you need to seperate your impex header from your data by a new line:
INSERT_UPDATE UsersFindCronJob;code[unique=true];job(code);firstName
;usersFindCronJob;usersFindJob;Mouad
Then you also missed the part where you create the Job itself:
INSERT_UPDATE ServicelayerJob;code[unique=true];springId;
;usersFindJob;usersFindJob
When you create your custom cronjob,then you need to update the "Custom Cronjob" you created.
****What mistake we do is updating these below statements when we write custom cronjob:****
INSERT_UPDATE ServicelayerJob;code[unique=true];springId;
INSERT_UPDATE Cronjob;code[unique=true];job(code);singleExecutable;sessionLanguage(isocode)
****Actually we need to write these below statements:****
INSERT_UPDATE ServicelayerJob;code[unique=true];springId;
INSERT_UPDATE ;code[unique=true];job(code);singleExecutable;sessionLanguage(isocode)
Please note that,if the attributes you added in custom cronjob are mandatory then you need to update those attributes as well,like:
INSERT_UPDATE ;code[unique=true];job(code);singleExecutable;sessionLanguage(isocode);
I'm new to CXF and JAXB. I'm having problems with a RESTful client that calls a external web service. I think I've followed the steps necessary to do this but I'm getting the following error when executing the client:
SEVERE: No message body reader has been found for class com.jaxb.AcXML, ContentType: text/html
Exception in thread "main" javax.ws.rs.client.ResponseProcessingException: No message body reader has been found for class com.jaxb.AcXML, ContentType: text/html
at org.apache.cxf.jaxrs.impl.ResponseImpl.reportMessageHandlerProblem(ResponseImpl.java:433)
at org.apache.cxf.jaxrs.impl.ResponseImpl.doReadEntity(ResponseImpl.java:384)
at org.apache.cxf.jaxrs.client.AbstractClient.readBody(AbstractClient.java:512)
at org.apache.cxf.jaxrs.client.WebClient.handleResponse(WebClient.java:1173)
at org.apache.cxf.jaxrs.client.WebClient.doResponse(WebClient.java:1156)
at org.apache.cxf.jaxrs.client.WebClient.doChainedInvocation(WebClient.java:1092)
at org.apache.cxf.jaxrs.client.WebClient.doInvoke(WebClient.java:894)
at org.apache.cxf.jaxrs.client.WebClient.doInvoke(WebClient.java:865)
at org.apache.cxf.jaxrs.client.WebClient.invoke(WebClient.java:428)
at org.apache.cxf.jaxrs.client.WebClient.get(WebClient.java:611)
at com.ws.GetOpenPO.getOpenPOs(GetOpenPO.java:58)
at com.ws.GetOpenPO.main(GetOpenPO.java:79)
My IDE is Eclipse Indigo. I've created a Dynamic Web Project and included the CXF 2.x Web Services, JAX-RS and JAXB facets. Below is the class I'm testing with:
package com.ws;
import java.text.MessageFormat;
import javax.ws.rs.core.MediaType;
import org.apache.cxf.jaxrs.client.WebClient;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import com.jaxb.AcXML;
public class GetOpenPO {
private String baseUrl;
public AcXML getOpenPOs( )
{
// Create a WebClient pointing to the base URL of the RESTful web service
WebClient client = WebClient.create( baseUrl ).path("GetOpenPOs");
HTTPConduit http = WebClient.getConfig(client).getHttpConduit();
HTTPClientPolicy httpClientPolicy=new HTTPClientPolicy();
httpClientPolicy.setReceiveTimeout(1000000);
httpClientPolicy.setConnectionTimeout(1000000);
httpClientPolicy.setProxyServer("proxy1.global.mycompany.com");
httpClientPolicy.setProxyServerPort(8080);
http.setClient(httpClientPolicy);
// Set the path from which we wish to get the object, request XML, and use JAXB
AcXML POs= client.accept(MediaType.APPLICATION_XML)
.query("U", "parm1")
.query("P", "parm2")
.query("N", "parm3")
.query("Processed", "parm4")
.query("StationEnd", "")
.get( AcXML.class);
return POs;
}
public String getBaseUrl()
{
return baseUrl;
}
public void setBaseUrl( String baseUrl )
{
this.baseUrl = baseUrl;
}
public static void main(String args[]){
GetOpenPO x = new GetOpenPO ();
x.setBaseUrl("http://www24.externalws.net/webservices/webservices.asmx");
AcXML openPOs = x.getOpenPOs();
}
}
I was able to call the webservice via my browser, which returns an XML document. Using this XML I created a schema and then using the "JAXB Classes from Schema" wizard in Eclipse the JAXB objects were generated. Below is the source file for the AcXML entity that I'm trying to retrieve via the client:
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2015.08.05 at 10:18:48 AM EDT
//
package com.jaxb;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType>
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element ref="{https://www.externalws.net/acXMLSchema.xsd}Header"/>
* <element ref="{https://www.externalws.net/acXMLSchema.xsd}Request"/>
* </sequence>
* <attribute name="lang" use="required">
* <simpleType>
* <restriction base="{http://www.w3.org/2001/XMLSchema} string">
* </restriction>
* </simpleType>
* </attribute>
* </restriction>
* </complexContent>
* </complexType>
* </pre>
*
*
*/
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"header",
"request"
})
#XmlRootElement(name = "acXML")
public class AcXML {
#XmlElement(name = "Header", required = true)
protected Header header;
#XmlElement(name = "Request", required = true)
protected Request request;
#XmlAttribute(name = "lang", required = true)
protected String lang;
/**
* Gets the value of the header property.
*
* #return
* possible object is
* {#link Header }
*
*/
public Header getHeader() {
return header;
}
/**
* Sets the value of the header property.
*
* #param value
* allowed object is
* {#link Header }
*
*/
public void setHeader(Header value) {
this.header = value;
}
/**
* Gets the value of the request property.
*
* #return
* possible object is
* {#link Request }
*
*/
public Request getRequest() {
return request;
}
/**
* Sets the value of the request property.
*
* #param value
* allowed object is
* {#link Request }
*
*/
public void setRequest(Request value) {
this.request = value;
}
/**
* Gets the value of the lang property.
*
* #return
* possible object is
* {#link String }
*
*/
public String getLang() {
return lang;
}
/**
* Sets the value of the lang property.
*
* #param value
* allowed object is
* {#link String }
*
*/
public void setLang(String value) {
this.lang = value;
}
}
Can someone tell me what I'm doing wrong or what am I missing that's causing the client to fail?
Thank You.
Add JAXBProvider
List<JAXBElementProvider> list = new ArrayList<JAXBElementProvider>();
list.add(new JAXBElementProvider());
WebClient client = WebClient.create( baseUrl, list).path("GetOpenPOs");
How can I set the default value in field.
In my document I need to set default value false for field emailnotify
In mogodb th default value should be zero.
Check my document
namespace xxx\xxxBundle\Document;
use FOS\UserBundle\Document\User as BaseUser;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
*/
class User extends BaseUser
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/**
* #MongoDB\Boolean
*/
protected $emailnotify;
/**
* Sets the emailnotify.
*
* #param boolean $emailnotify
*
* #return User
*/
public function setEmailnotify($emailnotify)
{
$this->emailnotify = (Boolean) $emailnotify;
return $this;
}
/**
* #return boolean
*/
public function isEmailnotify()
{
return $this->emailnotify;
}
}
I have found that setting the default value in the constructor works
public function __construct() {
$this->emailnotify = false;
}
Of course just setting the class variable to false will work for most parts if you use Doctrine to fetch the Document again afterwards, but the property will not be persisted to MongoDB like with the above.
For the follwing example XML input:
<Participants course="someCourse">
<workers>
<Worker ref="p3">
<Worker ref="p2">
</workers>
<Trainer ref="p1"/>
</Participants>
<Group id="group1" name="some mixed Person group">
<trainers>
<Trainer id="p1" name="John Doe">
</trainers>
<workers>
<Worker id="p2" name="Jim Scott">
<Worker id="p3" name="Walter Peace">
</workers>
</Group>
I am trying to make sure that the PersonList in Participants points to the Persons read from group1. (see code snipptes below for the JaxB annotations used). This is just an example for the more generic
approach I am seeking. I need to be generally able to follow id="" and ref="" attributes in a way
that the list elements are correctly unmarshalled as references.
With an UnmarshalListener and Unmarshalling twice I get around the problem of the references from the ref attribute to the id attribute. In the first phase the lookup Map is filled from the id attributes. In the second phase the refs are looked up. Unfortunately this solution will create copies instead of references. I could use the parent object to fix this but I am looking for a more generic solution. What would be a good way to achieve the proper dereferencing using ref/id attributes in the manner shown?
/**
* intercept the unmarshalling
*/
public static class ModelElementMarshallerListener extends javax.xml.bind.Unmarshaller.Listener {
public Map<String,Person> lookup=new HashMap<String,Person>();
#Override
public void afterUnmarshal(java.lang.Object target, java.lang.Object parent) {
if (target instanceof Person) {
person=(Person) target;
if (person.getId()!=null) {
lookup.put(person.getId(), person);
}
if (person.getRef()!=null) {
if (lookup.containsKey(person.getRef())) {
Person personRef=lookup.get(person.getRef());
person.copyFrom(personRef);
person.setRef(null);
}
}
}
}
}
#XmlRootElement(name="Participants")
public class Participants {
private List<Worker> workers;
/**
* getter for List<Worker> workers
* #return workers
*/
#XmlElementWrapper(name="workers")
#XmlElement(name="Worker", type=Worker.class)
public List<Worker> getWorkers() {
return workers;
}
...
}
#XmlRootElement(name="Group")
public class Group {
private List<Worker> workers;
/**
* getter for List<Worker> workers
* #return workers
*/
#XmlElementWrapper(name="workers")
#XmlElement(name="Worker", type=Worker.class)
public List<Worker> getWorkers() {
return workers;
}
...
}
#XmlRootElement(name="Trainer")
public class Trainer extends Person {}
#XmlRootElement(name="Worker")
public class Worker extends Person {}
#XmlRootElement(name="Person")
public class Person {
private String name;
/**
* getter for xsd:string/String name
* #return name
*/
#XmlAttribute(name="name")
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
private String ref;
/**
* getter for xsd:string/String id
* #return id
*/
#XmlAttribute(name="ref")
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref=ref;
}
private String id;
/**
* getter for xsd:string/String id
* #return id
*/
#XmlAttribute(name="id")
#XmlID
public String getId() {
this.id;
}
/**
* setter for xsd:string/String id
* #param pid - new value for id
*/
public void setId(String pid) {
this.id=pid;
}
}
To better illustrate the point I have modified the question to fit his answer. There is now a generic base class Person and I am trying to use it as per Can generic XmlAdapter be written
I solved the issue of being able to actually make sure the Adapters are used by writing specific derived Classes and using them with #XmlJavaTypeAdapter. I preregister the adapters using:
JAXBContext context = JAXBContext.newInstance(type);
Unmarshaller u = context.createUnmarshaller();
u.setAdapter(Worker.WorkerAdapter.class,new Worker.WorkerAdapter());
u.setAdapter(Trainer.TrainerAdapter.class,new Trainer.TrainerAdapter());
and then unmarshalling twice. The debug shows that the Adapter instance for both passes is the same. Still the lookup somehow seemed to fail ... The reason was the way the #XmlJavaTypeAdapter annotation works see:
What package-info do I annotate with XmlJavaTypeAdapters?
There seem to be multiple modes for #XmlJavaTypeAdapter:
it can be an annotation for a class
it can be an annotation for a field (getter)
it can be used in a package-info.java file to annotate a whole package
At this point I am using all three annotations and now have to debug which ones are necessary. I assume the global annotations (class,package) are not working as expected. The reason might be the type= usage in the #XmlElementWrapper which explicitly calls for a type. Personally I do not understand what is going on yet. At least things are now working as expected.
the local field annotation is now e.g.:
#XmlElementWrapper(name="workers")
#XmlElement(name="Worker", type=Worker.class)
#XmlJavaTypeAdapter(WorkerAdapter.class)
the package-info.java annotation is:
#XmlJavaTypeAdapters({
#XmlJavaTypeAdapter(value=WorkerAdapter.class,type=Worker.class),
#XmlJavaTypeAdapter(value=TrainerAdapter.class,type=Trainer.class),
})
package com.bitplan.jaxb.refidtest;
import javax.xml.bind.annotation.adapters.*;
the class annotation is:
#XmlJavaTypeAdapter(Worker.WorkerAdapter.class)
public class Worker extends Person {
...
/**
* Worker Adapter
* #author wf
*
*/
public static class WorkerAdapter extends PersonAdapter<Worker>{
#Override
public Worker marshal(Worker me)
throws Exception {
return super.marshal(me);
}
#Override
public Worker unmarshal(Worker me) throws Exception {
return super.unmarshal(me);
}
}
/**
* https://stackoverflow.com/questions/7587095/can-jaxb-marshal-by-containment-at-first-then-marshal-by-xmlidref-for-subsequen/7587727#7587727
* #author wf
*
*/
public class PersonAdapter<T extends Person> extends XmlAdapter<T, T>{
public boolean debug=true;
/**
* keep track of the elements already seen
*/
public Map<String,T> lookup=new HashMap<String,T>();
#Override
public T marshal(T me)
throws Exception {
return me;
}
/**
* show debug information
* #param title
* #param key
* #param me
* #param found
*/
public void showDebug(String title,String key,T me, T found) {
String deref="?";
if (found!=null)
deref="->"+found.getId()+"("+found.getClass().getSimpleName()+")";
if (debug)
System.err.println(title+": "+key+"("+me.getClass().getSimpleName()+")"+deref+" - "+this);
}
#Override
public T unmarshal(T me) throws Exception {
if (me.getId()!=null) {
showDebug("id",me.getId(),me,null);
lookup.put(me.getId(), me);
return me;
}
if (me.getRef()!=null) {
if (lookup.containsKey(me.getRef())) {
T meRef=lookup.get(me.getRef());
showDebug("ref",me.getRef(),me,meRef);
me.setRef(null);
return meRef;
} else {
if (debug)
showDebug("ref",me.getRef(),me,null);
}
}
return me;
}
}
A lot of times in a Zend Framework 2 view I'll be calling $this->escapeHtml() to make sure my data is safe. Is there a way to switch this behaviour from a blacklist to a whitelist?
PS: Read an article from Padraic Brady that suggests that automatic escaping is a bad idea. Additional thoughts?
You could write your own ViewModel class which escapes data when variables are assigned to it.
Thanks to Robs comment, I extended the ZF2 ViewModel as follows:
namespace Application\View\Model;
use Zend\View\Model\ViewModel;
use Zend\View\Helper\EscapeHtml;
class EscapeViewModel extends ViewModel
{
/**
* #var Zend\View\Helper\EscapeHtml
*/
protected $escaper = null;
/**
* Proxy to set auto-escape option
*
* #param bool $autoEscape
* #return ViewModel
*/
public function autoEscape($autoEscape = true)
{
$this->options['auto_escape'] = (bool) $autoEscape;
return $this;
}
/**
* Property overloading: get variable value;
* auto-escape if auto-escape option is set
*
* #param string $name
* #return mixed
*/
public function __get($name)
{
if (!$this->__isset($name)) {
return;
}
$variables = $this->getVariables();
if($this->getOption('auto_escape'))
return $this->getEscaper()->escape($variables[$name]);
return $variables[$name];
}
/**
* Get instance of Escaper
*
* #return Zend\View\Helper\EscapeHtml
*/
public function getEscaper()
{
if (null === $this->escaper) {
$this->escaper = new EscapeHtml;
}
return $this->escaper;
}
}
In a Controller it could be used like this:
public function fooAction()
{
return new EscapeViewModel(array(
'foo' => '<i>bar</i>'
));
//Turn off auto-escaping:
return new EscapeViewModel(array(
'foo' => '<i>bar</i>'
),['auto_escape' => false]);
}
Question:
I would appreciate it if soemebody would comment, if this is best practice or if there is a better and ecp. more efficient and resource-saving way?