I have built an application to test injecting log information (Entering and Exiting) around classes. I have built it using spring and used the following example for building it.
http://static.springsource.org/spring/docs/2.5.5/reference/aop.html#aop-aj-ltw
It works great now but I have 2 issues:
Private methods are not included when the log is weaved around the method. Is there a setting in the xml settings for spring to allow private methods to be weaved or is there another way around this?
I have to include all packages that are to be weaved in the META-INF/aop.xml for this to be able to work. Is there a setting to be used so that the log information can be weaved for all classes created in the project without having to add the package name to the aop.xml.
Below I have included all code and xml that is used. As I said all is working fine except the 2 issues above. Please assist me.
app.java
package se.jpab.application;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
#Service
public class App
{
public static void main( String[] args )
{
ApplicationContext appContext = new ClassPathXmlApplicationContext( new String[] { "spring.xml" });
Client client = (Client) appContext.getBean("client");
Location clientLocation = (Location) appContext.getBean("location");
// Set all values
clientLocation.setAdress1("Adress 1");
clientLocation.setAdress2("Adress 2");
clientLocation.setBox("N/A");
clientLocation.setCity("City of Dallas");
client.setName("John Doe");
client.setUrl("http://www.url.com");
client.setLocation(clientLocation);
// Print out all values
System.out.println(client.getName());
System.out.println(client.getUrl());
System.out.println(client.getLocation().getAdress1());
System.out.println(client.getLocation().getAdress2() + " " + client.getLocation().getCity());
}
}
Client.java
package se.jpab.application;
import org.springframework.stereotype.Service;
#Service
public class Client {
String name;
String url;
Location location;
//Constructors
public Client(String custName, String custUrl, Location custLocation){
name = custName;
url = custUrl;
location = custLocation;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public Client(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
printThis(name);
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public void printThis(String inStr) {
System.out.println("PRIVAT METOD");
System.out.println("Inkommand sträng --> " + inStr);
}
}
Location.java
package se.jpab.application;
import org.springframework.stereotype.Service;
#Service
public class Location {
String city;
String adress1;
String adress2;
String box;
//Constructors
public Location (String city, String adress1, String adress2, String box){
this.city = city;
this.adress1 = adress1;
this.adress2 = adress2;
this.box = box;
}
public Location (){
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getAdress1() {
return adress1;
}
public void setAdress1(String adress1) {
this.adress1 = adress1;
}
public String getAdress2() {
return adress2;
}
public void setAdress2(String adress2) {
this.adress2 = adress2;
}
public String getBox() {
return box;
}
public void setBox(String box) {
this.box = box;
}
}
aop.xml
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver options=" -showWeaveInfo">
<!-- only weave classes in our application-specific packages -->
<include within="se.jpab.application.*"/>
<include within="se.jpab.aspect.*"/>
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="se.jpab.aspect.InjectLogg"/>
</aspects>
</aspectj>
Aspect
package se.jpab.aspect;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
#Aspect
public class InjectLogg {
private static final Log fallbackLogger = LogFactory.getLog(InjectLogg.class);
#Around("execution(public * se.jpab.application..*.*(..))")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
Object invoker = pjp.getThis();
Log logger;
logger = LogFactory.getLog(getClassNameFrom(invoker.getClass()));
// Start injecting logg messages on entering a method.
logger.info("ENTERING: (" + pjp.getSignature().getName() + ")");
try {
logger.info("ARGUMENTS: " + Arrays.toString(pjp.getArgs()) + ")");
} catch (NullPointerException e) {
logger.info("ARGUMENTS: No arguments");
}
try {
// proceed to original method call
Object result = pjp.proceed();
// Injecting exiting messages after method is finished
logger.info("RESULT: " + result);
logger.info("EXITING: (" + pjp.getSignature().getName() + ")");
// Return the result of the method we are logging
return result;
} catch (IllegalArgumentException e) {
// same with ThrowsAdvice
logger.info("Exception. Throws IllegalArgumentException");
throw e;
}
}
private String getClassNameFrom(Class invokerClassName) {
// Function that ....... To be continued JP
// Add check for that string contains $$ and se.goteborg if not then
// return fallback logger class.
String[] classNameParts = invokerClassName.getName().split("$$");
int positionOfPackageName = classNameParts[0].indexOf("se.jpab");
String className = classNameParts[0].substring(positionOfPackageName);
return className;
}
}
Spring configuration (spring.xml)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:load-time-weaver/>
<context:annotation-config />
<context:component-scan base-package="se.jpab"/>
</beans>
Your first question:
Private methods are not included when the log is weaved around the
method. Is there a setting in the xml settings for spring to allow
private methods to be weaved or is there another way around this?
If you want to weave private methods, use full AspectJ and therein a privileged aspect, not Spring AOP. The Spring manual says:
If your interception needs include protected/private methods or even
constructors, consider the use of Spring-driven native AspectJ weaving
instead of Spring's proxy-based AOP framework. This constitutes a
different mode of AOP usage with different characteristics, so be sure
to make yourself familiar with weaving first before making a decision.
Your second question:
I have to include all packages that are to be weaved in the
META-INF/aop.xml for this to be able to work. Is there a setting to be
used so that the log information can be weaved for all classes created
in the project without having to add the package name to the aop.xml.
You can catch a package an all its subpackages with the .. syntax, e.g. se.jpab.application..* or even se.jpab..*. You can also combine several conditions with boolean operators. See the AspectJ documentation for examples.
Related
i have upgraded jakson api on spring boot 1.5.8 from jakson 2.8.0 to 2.10.0, since then mapping of object is behaving different.
when i am passing request body on springboot controller having propertyname cityCode
sample json
{
cityCode:DEL
}
when adding jsonproperty mapping works fine
#JsonProperty("cityCode")
private String cityCode;
but when i don't add #JsonProperty annotation
it looks for CityCode instead.
since json passed on request is
{
cityCode:DEL
}
it assing
object{cityCode=null}
please let me know if there is any property which i need to add on spring boot
because in most of my scenario i don't want to add #JsonProperty annotation to class fields
EDIT:
I enable log.level to trace i saw some message related to jackson
POJOPropertyBuilder - Unable to instantiate jackson 2.6 object. Using higher version of jackson.
EDIT2:
Adding Sample Model Class
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.List;
#JsonIgnoreProperties(ignoreUnknown = true)
#ApiModel(value = "CityRequest")
public class CityRequest implements Serializable {
private static final long serialVersionUID = 1L;
#ApiModelProperty
private String cityCode;
#ApiModelProperty
private String cityName;
#ApiModelProperty
private String area;
#ApiModelProperty
private List<String> areas;
public String getCityCode() {
return cityCode;
}
public void setCityCode(String cityCode) {
this.cityCode = cityCode;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
public List<String> getAreas() {
return areas;
}
public void setAreas(List<String> areas) {
this.areas = areas;
}
#Override
public String toString() {
return "CityRequest{" +
"cityCode='" + cityCode + '\'' +
", cityName='" + cityName + '\'' +
", area='" + area + '\'' +
", areas=" + areas +
'}';
}
}
on the controller method is being passed as
#ApiParam(value = "This field specifies the list of requests", required = true)
#Valid #RequestBody(required = true) CityRequest cityRequest
I haven't tried but maybe you can try changing the naming strategy to lowerCamelCase:
#JsonNaming(PropertyNamingStrategy.lowerCamelCase.class)
public class City {
private String cityCode;
}
You might want to give this a try as an app property to configure Jackson globally.
spring.jackson.property-naming-strategy=LOWER_CAMEL_CASE
I have used one java api on spring-boot application where object mapper naming strategy is being set to upper_camel_case.
since that class imported on App.java(#SpringBootApplication) upper_camel_case strategy being applied globally.
to fix this globally imposed upper_camel_case strategy i have override the object mapper configuration on App.java and removed
objectMapper.setPropertyNamingStrategy(new UpperCamelCaseStrategy());
now i am able to use default naming strategy on application.
I've a scenario where a bean I'm using has some fields populated from properties file while others need to be populated dynamically (from a api call).
Here is my bean:
#Configuration
#ConfigurationProperties(prefix="studio")
public class Studio {
private String areaCode; // loads from application.properties
private String hours; // loads from application.properties
private String groupCode; // loads from application.properties
private Address address; // loads from a api
private String id; // loads from a api
public Studio(String id, String city, String subdivision,
String addressLine1, String postalCode) {
Address address = Address.builder()
.street(addressLine1)
.city(city)
.postalCode(postalCode)
.state(subdivision)
.build();
this.id = id;
this.address = address;
}
}
Now the method that populates the dynamic fields is like this:
private List<Studio> getStudioDataFromApi(ResponseEntity<String> exchange)
throws Exception {
List<Studio> infoList = $(exchange.getBody())
.xpath("Area[TypeCode=\"CA\"]")
.map(
Area -> new Studio(
$(Area).child("Id").text(String.class),
$(Area).child("Address").child("City").text(String.class),
$(Area).child("Address").child("Subdivision").text(String.class),
$(Area).child("Address").child("AddressLine1").text(String.class),
$(Area).child("Address").child("PostalCode").text(String.class))
);
return infoList;
}
I Autowire Studio in that class. Now whenever I run this, I get the fields that are populated from the properties file as null. I can see the reason, which is, new doesn't know anything about the autowired bean. My question is how can I use both? i.e. use a bean that has always some fields populated from a config when its new-ed up.
Context xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean class="org.springframework.batch.core.scope.StepScope" />
<bean id="ItemReader" class="com.sdm.studio.reader.StudioReader" scope="step">
<property name="studio" ref="Studio" />
</bean>
<bean id="Studio" class="com.sdm.studio.domain.Studio" />
</bean>
[edit: full code example shown here is also on github ]
Try this:
//This class contains read-only properties, loaded from Spring Externalized Configuration
#Component
#ConfigurationProperties(prefix="studio")
public class Studio {
private String areacode; // loads from application.properties
//... also add other read-only properties and getters/setters...
public String getAreacode() {
return areacode;
}
public Studio setAreacode(String areacode) {
this.areacode = areacode;
return this;
}
}
//Just a POJO
class FullStudio {
private String id;
private Address address;
FullStudio(String id, String city, String areaCode) {
this.id = id;
this.address = new Address(id, city, areaCode);
}
#Override
public String toString() {
return "FullStudio{" +
"id='" + id + '\'' +
", address=" + address +
'}';
}
}
class Address{
String id;
String city;
String areaCode;
public Address(String id, String city, String areaCode) {
this.id = id;
this.city = city;
this.areaCode = areaCode;
}
#Override
public String toString() {
return "Address{" +
"id='" + id + '\'' +
", city='" + city + '\'' +
", areaCode='" + areaCode + '\'' +
'}';
}
}
What we are doing here is allowing Spring to control the lifecycle of the Studio class. You don't need to create a new Studio yourself. Spring does that when it starts up. Since it is also a #ConfigurationProperties class it will also populate values from Spring Externalized Configuration Note: you also need public getters and setters so that Spring can populate the values for you.
FullStudio is not a Spring managed class. You create your own FullStudio with values from Studio and any other api.
And here is a class that is not configured with Java Config #Configuration but instead is managed by an xml configuration:
public class StudioReader {
private Studio wiredstudio;
public String getMessage(){
return wiredstudio.getAreacode();
}
public StudioReader setWiredstudio(Studio studio) {
this.wiredstudio = studio;
return this;
}
}
And we use this mycontext.xml file to create this bean with the reference to wiredstudio. The Studio that Spring wires in here comes from our Studio instance configured with JavaConfig. The ref attribute of studio is the name that Spring automatically chose for us based on the name of the Studio class when it instantiated it into our spring application context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="studioReaderReader" class="com.example.StudioReader" >
<property name="wiredstudio" ref="studio" />
</bean>
</beans>
Personally, I think it is more trouble than its worth for new projects to combine xml and Java Configuration for Spring beans, but it can be done.
Here is a test class that shows how our Studio class can be used from classes created with Spring Java Config and XML config:
#RunWith(SpringRunner.class)
#SpringBootTest
public class StartAppTest {
#Autowired private Studio studio;
#Autowired private StudioReader studioReader;
#Test
public void contextok() throws Exception {
}
#Test
public void fullStudio() throws Exception {
FullStudio fs = new FullStudio("1", "Denver", studio.getAreacode());
System.out.println("stdio is: " + fs);
assertEquals("303", studio.getAreacode());
}
#Test
public void loadstudioreader() throws Exception {
assertEquals("303",studioReader.getMessage());
}
}
In order to run this test, you will need 2 more files:
#SpringBootApplication
#ImportResource("classpath:mycontext.xml")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
and our application.properties file:
studio.areacode=303
What are the maven dependencies need to be added to get the XML output without configuring content negotiation view resolver and managers. By using the default Message Converters based on jars on classpath (output based on accept headers). I am able to get the JSON output by having jackson-databind dependency on the classpath. For XML I am using
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.7</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${org.springframework.version}</version>
</dependency>
dependencies - I am unable to get the XML output. DO I need configure any Marshallers like Jaxb2Marsahllar as a bean in the configuration file. Can Any post the maven dependencies for JAXB2.
My Entity class:
package com.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.hibernate.validator.constraints.NotEmpty;
#Entity
#Table(name = "Employee")
#XmlRootElement
public class Employee {
public Employee() {
}
public Employee(Integer empno, String name, String dept, Double salary) {
this.empno = empno;
this.name = name;
this.dept = dept;
this.salary = salary;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer empno;
#Size(min = 1, max = 30)
#NotEmpty
private String name;
#NotEmpty
#Size(min = 1, max = 30)
private String dept;
/*
* #NotEmpty - cannot be set to double - supports String Collection Map
* arrays
*/
private Double salary;
#XmlAttribute
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
#XmlElement
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement
public String getDept() {
return dept;
}
public void setDept(String dept) {
this.dept = dept;
}
#XmlElement
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
#Override
public String toString() {
return "Employee [empno=" + empno + ", name=" + name + ", dept=" + dept
+ ", salary=" + salary + "]";
}
}
My Controller Class:
#Controller
public class EmployeeController {
#Autowired
EmployeeRepository employeeRepository;
#RequestMapping(value = "/employees", method=RequestMethod.GET,
produces= {MediaType.APPLICATION_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public #ResponseBody List<Employee> findAllXml(){
return employeeRepository.findAll();
}
}
Please Can any one say Whether the dependencies are enough ? What needs to be added..
put #XMLElement on set methods.
public Integer getEmpno() {
return empno;
}
#XmlAttribute
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getName() {
return name;
}
#XmlElement
public void setName(String name) {
this.name = name;
}
or you can use Spring Marshalling View of spring-oxm.jar
<bean id="xmlViewer"
class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.model.Employee</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
Update:1
Also findAll is returning list that list needs to be accomodated in a parent tag like
<Employees>
<Employee />
<Employee />
</Employees>
so you need to define a class that has an #XMLElement entity as List<Employees> create object of it put the data in it and return that object.
I found the answer to 406 exception
Problem was needed an extra configuration for Message Converters for XML output.
For XML Output, we need to Added a Message Converter to the list of Message converters of RequestMappingHandlerAdapter
But for JSON we dont need to do this explictly, based on the jackson-databind dependencies on the classpath, we can able get the JSON output. But for xml , we need to add a message converter (MarshallingHttpMessageConverter) .
Example: Using Java Based Config: configuring RequestMappingHandlerAdapter as a bean and adding required Message Converters...
#Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
List<HttpMessageConverter<?>> converters = new ArrayList();
converters.add(new MarshallingHttpMessageConverter(
new XStreamMarshaller()));
converters.add(new MappingJackson2HttpMessageConverter());
adapter.setMessageConverters(converters);
return adapter;
}
I am using XStream Marshaller, so need to add its dependencies as well
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.8</version>
</dependency>
Example Tests:
#Test
public void testXml() throws Exception {
this.mvc.perform(get("/employees/xml").accept(APPLICATION_XML))
.andDo(print())
.andExpect(content().contentType("application/xml"));
}
#Test
public void testJson() throws Exception {
this.mvc.perform(get("/employees/json").accept(APPLICATION_JSON))
.andDo(print())
.andExpect(content().contentType("application/json"));
}
Please post if you know any other way of doing this.
useful link: Spring XML 406 error
#XmlPath is not working.
Customer.java
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name= "Customer")
public class Customer {
private String CustomerId;
private String organizationCode;
private Extn extn;
private String organizationName;
private int reset;
private CustomerSchedulingPreferences customerSchedulingPreferences;
private ArrayList<RestrictedState> restrictedStateList;
#XmlAttribute
public String getCustomerId() {
return CustomerId;
}
public void setCustomerId(String customerId) {
CustomerId = customerId;
}
#XmlAttribute
public String getOrganizationCode() {
return organizationCode;
}
public void setOrganizationCode(String organizationCode) {
this.organizationCode = organizationCode;
}
#XmlElement(name="Extn")
public Extn getExtn() {
return extn;
}
public void setExtn(Extn extn) {
this.extn = extn;
}
#XmlPath("BuyerOrganization/#OrganizationName")
public String getOrganizationName() {
return organizationName;
}
public void setOrganizationName(String organizationName) {
this.organizationName = organizationName;
}
#XmlPath("BuyerOrganization/Extn/USSCORestrictedStateList")
#XmlElement(name = "USSCORestrictedState")
public ArrayList<RestrictedState> getRestrictedStateList() {
return restrictedStateList;
}
public void setRestrictedStateList(ArrayList<RestrictedState> restrictedStateList) {
this.restrictedStateList = restrictedStateList;
}
#XmlPath("BuyerOrganization/Extn/USSCORestrictedStateList/#Reset")
public int getReset() {
return reset;
}
public void setReset(int reset) {
this.reset = reset;
}
#XmlElement(name="CustomerSchedulingPreferences")
public CustomerSchedulingPreferences getCustomerSchedulingPreferences() {
return customerSchedulingPreferences;
}
public void setCustomerSchedulingPreferences(
CustomerSchedulingPreferences customerSchedulingPreferences) {
this.customerSchedulingPreferences = customerSchedulingPreferences;
}
}
Client.java
import javax.xml.transform.stream.StreamResult;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.oxm.Marshaller;
public class Client
{
public static void main(String[] args)throws IOException
{
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Marshaller marshaller = (Marshaller)context.getBean("jaxbMarshallerBean");
Customer customer=new Customer();
customer.setCustomerId("12345");
customer.setOrganizationCode("SUPPLY");
Extn extn = new Extn();
extn.setExtnBillCreditCode("000");
extn.setExtnBillSubscriptionId("132131");
customer.setExtn(extn);
RestrictedState resState1= new RestrictedState();
resState1.setOrgCode("952121");
resState1.setRestrictedStateCode("IN");
RestrictedState resState2= new RestrictedState();
resState2.setOrgCode("60325");
resState2.setRestrictedStateCode("IL");
ArrayList<RestrictedState> restrictedStateList = new ArrayList<RestrictedState>();
restrictedStateList.add(resState1);
restrictedStateList.add(resState2);
CustomerSchedulingPreferences custSchedPref = new CustomerSchedulingPreferences();
custSchedPref.setIsLineShipComplete("Y");
custSchedPref.setIsLineShipSingleNode("N");
custSchedPref.setOptimizationType("03");
customer.setCustomerSchedulingPreferences(custSchedPref);
customer.setRestrictedStateList(restrictedStateList);
marshaller.marshal(customer, new StreamResult(new FileWriter("customer.xml")));
System.out.println("XML Created Sucessfully");
}
}
applicationContext.Xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
<oxm:jaxb2-marshaller id="jaxbMarshallerBean">
<oxm:class-to-be-bound name="com.javatpoint.Customer"/>
</oxm:jaxb2-marshaller>
</beans>
Structure of Output needed :
<Customer CustomerID="952121" OrganizationCode="SUPPLY" >
<Extn ExtnBillCreditCode="000" ExtnBillSubscriptionID="952121" />
<BuyerOrganization OrganizationName="Buy.com1" >
<Extn>
<USSCORestrictedStateList Reset="Y">
<USSCORestrictedState OrganizationCode="952121" RestrictedStateCode="IN"/>
</USSCORestrictedStateList>
</Extn>
</BuyerOrganization>
<CustomerSchedulingPreferences IsLineShipComplete="" IsLineShipSingleNode="" />
</Customer>
================================================================================
Please help me in resolving this:
Currently i am getting output like below :
<Customer organizationCode="SUPPLY" customerId="12345">
<CustomerSchedulingPreferences IsLineShipSingleNode="N" IsLineShipComplete="Y"/>
<Extn ExtnBillSubscriptionID="132131" ExtnBillCreditCode="000"/>
<reset>0</reset>
<USSCORestrictedState restrictedStateCode="IN" OrganizationCode="952121"/>
<USSCORestrictedState restrictedStateCode="IL" OrganizationCode="60325"/>
</Customer>
To leverage the #XmlPath extension you need to be using EclipseLink MOXy as your JAXB provider.
eclipselink.jar on your classpath
a jaxb.properties file in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html)
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Below is a link that will help set this up:
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/Spring
what's wrong with my accounting example? The Calculator bean doesn't get injected into the Accoount. There is a null-pointer-exception in the deposit method because calculator is null.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/META-INF/spring/context.xml")
public class DITestJavaTest extends Assert {
#Test
public void diTest() {
Account account = new Account(500);
account.deposit(500);
assertEquals("balance is 1000", 1000, account.getBalance(), 0.0001);
}
}
public class Account {
#Autowired
private ICalculator calculator;
private double balance;
public Account() {
balance = 0;
}
public Account(double balance) {
this.balance = balance;
}
public void deposit(double amount) {
balance = calculator.add(balance, amount);
}
public void withdraw(double amount) {
balance = calculator.subtract(balance, amount);
}
public double getBalance() {
return balance;
}
}
#Component
public class Calculator implements ICalculator {
#Override
public double add(double summand1, double summand2) {
System.out.println("Main implementation with " + Calculator.class.getName() + "addition");
BigDecimal result = round(summand1 + summand2);
return result.doubleValue();
}
#Override
public double subtract(double minuend, double subtrahend) {
System.out.println("Main implementation with " + Calculator.class.getName() + "subtraction");
BigDecimal result = round(minuend - subtrahend);
return result.doubleValue();
}
private BigDecimal round(double amount) {
return new BigDecimal(amount).setScale(2, BigDecimal.ROUND_HALF_UP);
}
}
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.example.banking" />
<context:annotation-config />
</beans>
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/META-INF/spring/context.xml")
public class DITestJavaTest extends Assert {
#Autowired
Account account
#Test
public void diTest() {
account.deposit(500);
account.deposit(500);
assertEquals("balance is 1000", 1000, account.getBalance(), 0.0001);
}
}
Don't initialize account in your test. This way it's not managed by Spring and the Calculator is never injected
And as suggested, annotate Account with #Component
You need to anotate Account class as well to tell spring that it contains annotated member.
Somethng like
#Component
public class Account { ... }