JAXB Moxy- Question on how to annotate field that is xsd complex type - annotations

I am getting started with JaxB and am using the Moxy implementation. I have an industry standard xsd that I converted to Java Object Model using Jaxb. I have gotten as far as annotating simple fields like string,integer and date.
I have been searching and need to be pointed in the right direction to annotate the following field which is a xsd complex type which has 4 attributes and an optional string element. A subset of the generated code is as follows:
Conditions.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"condition"
})
#XmlRootElement(name = "conditions")
public class Conditions {
protected List<Conditions.Condition> condition;
public List<Conditions.Condition> getCondition() {
if (condition == null) {
condition = new ArrayList<Conditions.Condition>();
}
return this.condition;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"problemDate",
"problemType",
"problemCode",
"problemStatus",
})
public static class Condition {
protected IvlTs problemDate;
//This is the field I need to annotate (problemType)
protected Cd problemType;
//The 2 below fields (problemCode, problemStatus) will also have to be annotated but I am just focusing on problemType for now
protected Cd problemCode;
protected Ce problemStatus
public void setProblemDate(IvlTs value) {
this.problemDate = value;
}
public void setProblemType(Cd value) {
this.problemType = value;
}
public void setProblemCode(Cd value) {
this.problemCode = value;
}
public void setProblemStatus(Ce value) {
this.problemStatus = value;
}
//omitted getters
}
Cd.java
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "cd", propOrder = {
"originalText",
})
public class Cd {
protected Object originalText;
#XmlAttribute(name = "code")
#XmlSchemaType(name = "anySimpleType")
protected String code;
#XmlAttribute(name = "displayName")
#XmlSchemaType(name = "anySimpleType")
protected String displayName;
#XmlAttribute(name = "codeSystem")
#XmlSchemaType(name = "anySimpleType")
protected String codeSystem;
#XmlAttribute(name = "codeSystemName")
#XmlSchemaType(name = "anySimpleType")
protected String codeSystemName;
#XmlAttribute(name = "nullFlavor")
protected NullFlavorType nullFlavor;
//ommitted getters and setters
The Cd.java class will be used for a number of other classes, not only in the Conditions.java class.
My question in particular is how would I annotate my fields for problemType in Conditions.java, where problemType has 4 attributes and one optional element.
I will not be able to directly annotate Cd.java as the xml input will differ depending on what class I am implementing (choice of 8 other classes that use Cd.java class). The existing annotations above were auto-generated by Jaxb The xml input for the Conditions.java problemType is as follows:
<PROBLEM_MODULE>
<code>24434</code> //Maps to protected String code in Cd.java;
<codeName>ICD-9</codeName> //Maps to protected String codeSystem in Cd.java;
<display>Asthma</display> //Maps to protected String displayName in Cd.java;
<codeSystem>2.564.34343.222</codeSystem> // Maps to protected String codeSystemName in Cd.java;
</PROBLEM_MODULE>
Please advise where I need to clarify my question. Ultimately I am requesting resources or tutorial to help me through this.
******UPDATE*******
Blaise's solution worked perfectly as I tested it on another project that is not as complex. Thus, the method is right, but there is something that I am getting wrong with the metadata file. I updated the Conditions.java file above, as I left out details that may effect the way I need to implement the metadata file.
My oxm.xml file
<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="conditions.exec"
xml-mapping-metadata-complete="true">
<java-types>
<java-type name="Conditions" xml-accessor-type="FIELD">
<xml-root-element name="PROBLEM_MODULE"/>
</java-type>
<java-type name="Cd" xml-accessor-type="FIELD">
<java-attributes>
<xml-type prop-order="code codeSystem displayName codeSystemName"/>
<xml-element java-attribute="codeSystem" name="codeName"/>
<xml-element java-attribute="displayName" name="display"/>
<xml-element java-attribute="codeSystemName" name="codeSystem"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
*Main Class*
public static void main(String[] args) {
try {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, new File("src/conditions/exec/oxm.xml"));
JAXBContext jc = JAXBContext.newInstance(new Class[] {Conditions.class,Cd.class}, properties);
// create an Unmarshaller
Unmarshaller u = jc.createUnmarshaller();
conditions.exec.Conditions InventoryInput = (conditions.exec.Conditions) u.unmarshal(
new File("src/conditions/exec/problems.xml")); //input file
// create a Marshaller and marshal to a file
Marshaller resultMarshaller = jc.createMarshaller();
resultMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
resultMarshaller.marshal(InventoryInput, System.out);
} catch (JAXBException je) {
je.printStackTrace();
}

You can leverage EclipseLink JAXB (MOXy)'s external binding file to apply a second mapping to your class:
oxm.xml
One thing that I have set in this file is xml-mapping-metadata-complete="true", this setting tells MOXy to ignore the annotations completely and just use this file. By default the OXM file is used to supplement the annotations.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum7043389"
xml-mapping-metadata-complete="true">
<java-types>
<java-type name="Root2">
<xml-root-element/>
</java-type>
<java-type name="Cd">
<xml-type prop-order="code codeSystem displayName codeSystemName"/>
<java-attributes>
<xml-element java-attribute="codeSystem" name="codeName"/>
<xml-element java-attribute="displayName" name="display"/>
<xml-element java-attribute="codeSystemName" name="codeSystem"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Demo
The oxm.xml file is passed in as a property to create the JAXBContext. In the example below jc1 is created on the classes and jc2 is created on the classes and oxm.xml
package forum7043389;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Cd cd = new Cd();
cd.setCode("24434");
cd.setCodeSystem("ICD-9");
cd.setDisplayName("Asthma");
cd.setCodeSystemName("2.564.34343.222");
JAXBContext jc1 = JAXBContext.newInstance(Root1.class);
Marshaller marshaller1 = jc1.createMarshaller();
marshaller1.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Root1 root1 = new Root1();
root1.setCd(cd);
marshaller1.marshal(root1, System.out);
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum7043389/oxm.xml");
JAXBContext jc2 = JAXBContext.newInstance(new Class[] {Root2.class}, properties);
Marshaller marshaller2 = jc2.createMarshaller();
marshaller2.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Root2 root2 = new Root2();
root2.setCd(cd);
marshaller2.marshal(root2, System.out);
}
}
Output
The following is the output from running the demo:
<?xml version="1.0" encoding="UTF-8"?>
<root1>
<cd code="24434" displayName="Asthma" codeSystem="ICD-9" codeSystemName="2.564.34343.222"/>
</root1>
<?xml version="1.0" encoding="UTF-8"?>
<root2>
<cd>
<code>24434</code>
<codeName>ICD-9</codeName>
<display>Asthma</display>
<codeSystem>2.564.34343.222</codeSystem>
</cd>
</root2>
Cd
package forum7043389;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "cd", propOrder = {"originalText",})
public class Cd {
protected Object originalText;
#XmlAttribute(name = "code")
#XmlSchemaType(name = "anySimpleType")
protected String code;
#XmlAttribute(name = "displayName")
#XmlSchemaType(name = "anySimpleType")
protected String displayName;
#XmlAttribute(name = "codeSystem")
#XmlSchemaType(name = "anySimpleType")
protected String codeSystem;
#XmlAttribute(name = "codeSystemName")
#XmlSchemaType(name = "anySimpleType")
protected String codeSystemName;
#XmlAttribute(name = "nullFlavor")
protected NullFlavorType nullFlavor;
public Object getOriginalText() {
return originalText;
}
public void setOriginalText(Object originalText) {
this.originalText = originalText;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getCodeSystem() {
return codeSystem;
}
public void setCodeSystem(String codeSystem) {
this.codeSystem = codeSystem;
}
public String getCodeSystemName() {
return codeSystemName;
}
public void setCodeSystemName(String codeSystemName) {
this.codeSystemName = codeSystemName;
}
public NullFlavorType getNullFlavor() {
return nullFlavor;
}
public void setNullFlavor(NullFlavorType nullFlavor) {
this.nullFlavor = nullFlavor;
}
}
Root1
package forum7043389;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Root1 {
private Cd cd;
public Cd getCd() {
return cd;
}
public void setCd(Cd cd) {
this.cd = cd;
}
}
Root2
package forum7043389;
public class Root2 {
private Cd cd;
public Cd getCd() {
return cd;
}
public void setCd(Cd cd) {
this.cd = cd;
}
}
For More Information
http://wiki.eclipse.org/EclipseLink/UserGuide/MOXy/Runtime/XML_Bindings
http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

Related

MongoRepository Save method does not insert in database

I have created a SpringBoot project with Jhipster. The database I am using is MongoDB.
In the application-dev.yml I have the following configuration:
data:
mongodb:
uri: mongodb://<user>:<pass>#<ip>:<port>
database: gateway
The user, password, ip Address, and port, in my application-dev are real values.
The DatabaseConfiguration.java is:
#Configuration
#EnableMongoRepositories("es.second.cdti.repository")
#Profile("!" + JHipsterConstants.SPRING_PROFILE_CLOUD)
#Import(value = MongoAutoConfiguration.class)
#EnableMongoAuditing(auditorAwareRef = "springSecurityAuditorAware")
public class DatabaseConfiguration {
private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
#Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(DateToZonedDateTimeConverter.INSTANCE);
converters.add(ZonedDateTimeToDateConverter.INSTANCE);
return new MongoCustomConversions(converters);
}
#Bean
public Mongobee mongobee(MongoClient mongoClient, MongoTemplate mongoTemplate, MongoProperties mongoProperties) {
log.debug("Configuring Mongobee");
Mongobee mongobee = new Mongobee(mongoClient);
mongobee.setDbName(mongoProperties.getMongoClientDatabase());
mongobee.setMongoTemplate(mongoTemplate);
// package to scan for migrations
mongobee.setChangeLogsScanPackage("es.second.cdti.config.dbmigrations");
mongobee.setEnabled(true);
return mongobee;
}}
The CloudDatabaseConfiguration is:
#Configuration
#EnableMongoRepositories("es.second.cdti.repository")
#Profile(JHipsterConstants.SPRING_PROFILE_CLOUD)
public class CloudDatabaseConfiguration extends AbstractCloudConfig {
private final Logger log = LoggerFactory.getLogger(CloudDatabaseConfiguration.class);
#Bean
public MongoDbFactory mongoFactory() {
return connectionFactory().mongoDbFactory();
}
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
#Bean
public ValidatingMongoEventListener validatingMongoEventListener() {
return new ValidatingMongoEventListener(validator());
}
#Bean
public MongoCustomConversions customConversions() {
List<Converter<?, ?>> converterList = new ArrayList<>();
converterList.add(DateToZonedDateTimeConverter.INSTANCE);
converterList.add(ZonedDateTimeToDateConverter.INSTANCE);
converterList.add(DurationToLongConverter.INSTANCE);
return new MongoCustomConversions(converterList);
}
#Bean
public Mongobee mongobee(MongoDbFactory mongoDbFactory, MongoTemplate mongoTemplate, Cloud cloud) {
log.debug("Configuring Cloud Mongobee");
List<ServiceInfo> matchingServiceInfos = cloud.getServiceInfos(MongoDbFactory.class);
if (matchingServiceInfos.size() != 1) {
throw new CloudException("No unique service matching MongoDbFactory found. Expected 1, found "
+ matchingServiceInfos.size());
}
MongoServiceInfo info = (MongoServiceInfo) matchingServiceInfos.get(0);
Mongobee mongobee = new Mongobee(info.getUri());
mongobee.setDbName(mongoDbFactory.getDb().getName());
mongobee.setMongoTemplate(mongoTemplate);
// package to scan for migrations
mongobee.setChangeLogsScanPackage("es.second.cdti.config.dbmigrations");
mongobee.setEnabled(true);
return mongobee;
}
}
The cdtiApp.java is:
#SpringBootApplication
#EnableConfigurationProperties({ApplicationProperties.class})
public class CdtiApp implements InitializingBean{
private static final Logger log = LoggerFactory.getLogger(CdtiApp.class);
private final Environment env;
public CdtiApp(Environment env) {
this.env = env;
}
/**
* Initializes cdti.
* <p>
* Spring profiles can be configured with a program argument --spring.profiles.active=your-active-profile
* <p>
* You can find more information on how profiles work with JHipster on https://www.jhipster.tech/profiles/.
*/
#PostConstruct
public void initApplication() {
Collection<String> activeProfiles = Arrays.asList(env.getActiveProfiles());
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) {
log.error("You have misconfigured your application! It should not run " +
"with both the 'dev' and 'prod' profiles at the same time.");
}
if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)) {
log.error("You have misconfigured your application! It should not " +
"run with both the 'dev' and 'cloud' profiles at the same time.");
}
}
/**
* Main method, used to run the application.
*
* #param args the command line arguments.
*/
public static void main(String[] args) {
SpringApplication app = new SpringApplication(CdtiApp.class);
DefaultProfileUtil.addDefaultProfile(app);
Environment env = app.run(args).getEnvironment();
logApplicationStartup(env);
}
private static void logApplicationStartup(Environment env) {
String protocol = "http";
if (env.getProperty("server.ssl.key-store") != null) {
protocol = "https";
}
String serverPort = env.getProperty("server.port");
String contextPath = env.getProperty("server.servlet.context-path");
if (StringUtils.isBlank(contextPath)) {
contextPath = "/";
}
String hostAddress = "localhost";
try {
hostAddress = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
log.warn("The host name could not be determined, using `localhost` as fallback");
}
log.info("\n----------------------------------------------------------\n\t" +
"Application '{}' is running! Access URLs:\n\t" +
"Local: \t\t{}://localhost:{}{}\n\t" +
"External: \t{}://{}:{}{}\n\t" +
"Profile(s): \t{}\n----------------------------------------------------------",
env.getProperty("spring.application.name"),
protocol,
serverPort,
contextPath,
protocol,
hostAddress,
serverPort,
contextPath,
env.getActiveProfiles());
String configServerStatus = env.getProperty("configserver.status");
if (configServerStatus == null) {
configServerStatus = "Not found or not setup for this application";
}
log.info("\n----------------------------------------------------------\n\t" +
"Config Server: \t{}\n----------------------------------------------------------", configServerStatus);
}
#Override
public void afterPropertiesSet() throws Exception {
// TODO Auto-generated method stub
}
}
The Vehicle entity:
#org.springframework.data.mongodb.core.mapping.Document(collection = "vehicle")
public class Vehicle implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String id;
#NotNull
#Field("plate")
private String plate;
#NotNull
#Field("registrationDate")
private Instant registrationDate;
#NotNull
#Field("brand")
private String brand;
#NotNull
#Field("model")
private String model;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPlate() {
return plate;
}
public void setPlate(String plate) {
this.plate = plate;
}
public Instant getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(Instant registrationDate) {
this.registrationDate = registrationDate;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
The VehicleDTO is:
public class VehicleDTO {
private String id;
private String plate;
private Instant registrationDate;
private String brand;
private String model;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPlate() {
return plate;
}
public void setPlate(String plate) {
this.plate = plate;
}
public Instant getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(Instant registrationDate) {
this.registrationDate = registrationDate;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
}
The VehicleMapper is:
#Mapper(componentModel = "spring")
public interface VehicleMapper{
Vehicle toEntity(VehicleDTO source);
VehicleDTO toDto(Vehicle target);
}
The VehicleResource is:
#RestController
#RequestMapping("/api")
#CrossOrigin(origins = "*", methods = { RequestMethod.GET, RequestMethod.POST })
public class VehicleResource {
private final Logger log = LoggerFactory.getLogger(VehicleResource.class);
#Value("${jhipster.clientApp.name}")
private String applicationName;
#Autowired
private final VehicleService vehicleService;
public VehicleResource(VehicleService vehicleService) {
this.vehicleService = vehicleService;
}
#PostMapping("/vehicle")
#PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
public ResponseEntity<Vehicle> createVehicle(#Valid #RequestBody VehicleDTO vehicleDTO) throws URISyntaxException {
log.debug("REST request to save Vehicle : {}", vehicleDTO);
Vehicle newVehicle = vehicleService.createVehicle(vehicleDTO);
return ResponseEntity.created(new URI("/api/vehicle/" + newVehicle.getPlate()))
.headers(HeaderUtil.createAlert(applicationName, "vehicleManagement.created", newVehicle.getPlate()))
.body(newVehicle);
}
}
The VehicleService interface is:
public interface VehicleService {
Vehicle createVehicle(VehicleDTO vehicleDTO);
}
The VehicleServiceImpl is:
#Service
public class VehicleServiceImpl implements VehicleService{
#Autowired
private final VehicleRepository vehicleRepository;
#Autowired
private final VehicleMapper mapper;
public VehicleServiceImpl(VehicleRepository vehicleRepository, VehicleMapper mapper) {
this.vehicleRepository = vehicleRepository;
this.mapper = mapper;
}
private final Logger log = LoggerFactory.getLogger(VehicleServiceImpl.class);
#Override
public Vehicle createVehicle(VehicleDTO vehicleDTO) {
Vehicle vehicle = vehicleRepository.save(mapper.toEntity(vehicleDTO));
log.debug("Created Information for vehicle: {}", vehicle);
return vehicle;
}
}
The VehicleRepository interface is:
/**
* Spring Data MongoDB repository for the {#link Vehicle} entity.
*/
#Repository
public interface VehicleRepository extends MongoRepository<Vehicle, String> {
}
From the Swagger console I access the Vehicle-Resource:
Swagger console
Click on the button and write in the text box the json with the vehicle data:
enter JSON data
As we can see in the following image, the answer is 201. Initially the vehicle was saved with the identifier "id": "60e740935ed5a10e2c2ed19e".
Send request
I access the database to check that the vehicle has been correctly stored in the vehicle table. To my surprise ... there is no vehicle in the vehicle table:
show database
I can make sure that the data in the database application-dev is OK. I don't have any other databases.
I suspect that transactions with the database are not actually being made. This data is somehow stored in memory because if I do a findAllVehicles from Swagger it does return the vehicle.
I have a eureka server running (jhipster-registry) and two microservices that synchronize with it. The Gateway, which acts as a reverse proxy and the Vehiculos microservice. The Swagger console is the gateway, from where I make the request to insert vehicles. Everything seems to work, but as I say in bbdd does not save anything.

multi-tenant application in spring - connecting to DB

Hi Experts,
I am working on a multi-tenant project. It's a table per tenant architecture.
We are using spring and JPA (eclipse-link) for this purpose.
Here our use case is when ever a new customer subscribes to our application a new data base would be created for the customer.
As spring configuration would be loaded only during start-up how to load this new db configuration at run time?
Could some one please give some pointers?
Thanks in advance.
BR,
kitty
For multitenan, first you need to create MultitenantConfig.java
like below file.
here tenants.get("Musa") is my tenant name, comes from application.properties file
#Configuration
#EnableConfigurationProperties(MultitenantProperties.class)
public class MultiTenantConfig extends WebMvcConfigurerAdapter {
/** The Constant log. */
private static final Logger log = LoggerFactory.getLogger(MultiTenantConfig.class);
/** The multitenant config. */
#Autowired
private MultitenantProperties multitenantConfig;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MultiTenancyInterceptor());
}
/**
* Data source.
*
* #return the data source
*/
#Bean
public DataSource dataSource() {
Map<Object, Object> tenants = getTenants();
MultitenantDataSource multitenantDataSource = new MultitenantDataSource();
multitenantDataSource.setDefaultTargetDataSource(tenants.get("Musa"));
multitenantDataSource.setTargetDataSources(tenants);
// Call this to finalize the initialization of the data source.
multitenantDataSource.afterPropertiesSet();
return multitenantDataSource;
}
/**
* Gets the tenants.
*
* #return the tenants
*/
private Map<Object, Object> getTenants() {
Map<Object, Object> resolvedDataSources = new HashMap<>();
for (Tenant tenant : multitenantConfig.getTenants()) {
DataSourceBuilder dataSourceBuilder = new DataSourceBuilder(this.getClass().getClassLoader());
dataSourceBuilder.driverClassName(tenant.getDriverClassName()).url(tenant.getUrl())
.username(tenant.getUsername()).password(tenant.getPassword());
DataSource datasource = dataSourceBuilder.build();
for (String prop : tenant.getTomcat().keySet()) {
try {
BeanUtils.setProperty(datasource, prop, tenant.getTomcat().get(prop));
} catch (IllegalAccessException | InvocationTargetException e) {
log.error("Could not set property " + prop + " on datasource " + datasource);
}
}
log.info(datasource.toString());
resolvedDataSources.put(tenant.getName(), datasource);
}
return resolvedDataSources;
}
}
public class MultitenantDataSource extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
return TenantContext.getCurrentTenant();
}
}
public class MultiTenancyInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
TenantContext.setCurrentTenant("Musa");
return true;
}
}
#ConfigurationProperties(prefix = "multitenancy")
public class MultitenantProperties {
public static final String CURRENT_TENANT_IDENTIFIER = "tenantId";
public static final int CURRENT_TENANT_SCOPE = 0;
private List<Tenant> tenants;
public List<Tenant> getTenants() {
return tenants;
}
public void setTenants(List<Tenant> tenants) {
this.tenants = tenants;
}
}
public class Tenant {
private String name;
private String url;
private String driverClassName;
private String username;
private String password;
private Map<String,String> tomcat;
//setter gettter
public class TenantContext {
private static ThreadLocal<Object> currentTenant = new ThreadLocal<>();
public static void setCurrentTenant(Object tenant) {
currentTenant.set(tenant);
}
public static Object getCurrentTenant() {
return currentTenant.get();
}
}
add below properties in application.properties
multitenancy.tenants[0].name=Musa
multitenancy.tenants[0].url<url>
multitenancy.tenants[0].username=<username>
multitenancy.tenants[0].password=<password>
multitenancy.tenants[0].driver-class-name=<driverclass>

XML attributes are not parsed in karaf

In karaf 4.0.3, XML attributes are not parsed via JAXB. The same application works with Eclipse internal OSGI container, but fails with karaf container.
JDK7 JAXB implementation is used in both cases.
Any ideas why it fails?
Incoming XML:
<?xml version="1.0" encoding="iso-8859-1"?>
<responsible version="1.0">
</responsible>
Parse method:
public void start(BundleContext bundleContext) throws Exception {
Activator.context = bundleContext;
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(new Thread() {
public void run() {
try {
System.out.println("===============================================");
String name = "Responsible-response.xml";
Class<com.log4j2test.pojo.Responsible> baseClass = com.log4j2test.pojo.Responsible.class;
JAXBContext context = JAXBContext.newInstance(baseClass);
Unmarshaller u = context.createUnmarshaller();
final InputStream is = this.getClass().getResourceAsStream(name);
final InputStream is2 = this.getClass().getResourceAsStream(name);
String incomingXml = convertStreamToString(is2);
System.out.println("===Incoming XML: \n" + incomingXml);
StreamSource source = new StreamSource(is);
JAXBElement<?> unmarshaled = u.unmarshal(source, baseClass);
Object po = unmarshaled.getValue();
System.out.println("===Parsed POJO: " + po);
} catch (Throwable e) {
e.printStackTrace();
}
}
}, 5, 5, TimeUnit.SECONDS);
}
The POJO:
#XmlRootElement(name = "responsible")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "responsible", propOrder = { "version" })
public class Responsible {
#XmlAttribute(name = "version")
protected Double version;
public Double getVersion() {
return version;
}
public void setVersion(Double version) {
this.version = version;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("Responsible [");
builder.append("version=");
builder.append(version);
builder.append("]");
return builder.toString();
}
Output in KARAF:
Output in Eclipse:
Adding javax.xml.bind solved the problem:
karaf/etc/config.properties:
org.osgi.framework.bootdelegation = \
javax.xml.bind, \

Execute Stored Procedure in JPA 2.0

I have the following problem and I do not how to solve it.
I have a stored procedure with one parameter ( a date in the format: yyyy-MM-dd ) on my MSSQL Server 2008.
Then I have an #Entity class with a #NamedNativeQuery:
#NamedNativeQuery(name = "my_stored_proc",query = "? = exec EMIR_GUI.get_OTCLite_ACKNACK_Report ?", resultClass = EmirFacade.class)
#Entity
public class EmirFacade {
#Column(name="MessageType", nullable=false)
#Basic(fetch = FetchType.EAGER)
private String mesageType;
My Bean class looks like this:
#PersistenceContext(unitName=Globals.__TWHUNITNAME)
private EntityManager em;
public List<EmirFacade> get_EmirReport(Date date) {
try {
#SuppressWarnings("unchecked")
Query q = em.createNamedQuery("my_stored_proc").setParameter(1, date);
List<EmirFacade> emir_report = q.getResultList();
//List emir_report = q.getResultList();
return emir_report;
} catch (Exception e) {
return Collections.emptyList();
}
}
Now, I always get back the following error message ( it is in german, so I have to translate it as good as I can )
Index "0" is out of range.
I tried nearly everything but I cannot find any way to solve my problem.
Maybe, somebody has a good suggestion for me?
Thank you very much!
JPA 2.0 has no explicit support for stored procedures (JPA 2.1 has).
One workaround is to use native queries (like {CALL APURARCAMPANHASBRINDES.PROC_APURARCAMPANHA(?1, ?2, ?3, ?4, ?5, ?6, ?7)}), but that doesn’t work when the procedure has out-parameters.
Here is a sample implementation that uses Hibernate’s Work interface:
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.hibernate.Session;
import org.hibernate.jdbc.Work;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
public class CampanhaBrindesStoredProcedure {
#PersistenceContext
private EntityManager entityManager;
private String mensagem;
private String geroubrinde;
#Transactional
public void apurarCampamha(Long numeroPedido, String codigoFilialNF,
String cgcEntCGCENT, Long numeroSequencia, String integradora) {
try {
MyStoredProc storedProc = new MyStoredProc(numeroPedido, codigoFilialNF,
cgcEntCGCENT, numeroSequencia, integradora);
entityManager.unwrap(Session.class).doWork(storedProc);
setGeroubrinde(storedProc.getGeroubrinde());
setMensagem(storedProc.getMensagem());
} catch (Exception e) {
e.printStackTrace();
}
}
public String getGeroubrinde() {
return geroubrinde;
}
public void setGeroubrinde(String geroubrinde) {
this.geroubrinde = geroubrinde;
}
public String getMensagem() {
return mensagem;
}
public void setMensagem(String mensagem) {
this.mensagem = mensagem;
}
private static final class MyStoredProc implements Work {
private final Long numeroPedido;
private final String codigoFilialNF;
private final String cgcEntCGCENT;
private final Long numeroSequencia;
private final String integradora;
private String mensagem;
private String geroubrinde;
private MyStoredProc(Long numeroPedido, String codigoFilialNF,
String cgcEntCGCENT, Long numeroSequencia, String integradora) {
this.numeroPedido = numeroPedido;
this.codigoFilialNF = codigoFilialNF;
this.cgcEntCGCENT = cgcEntCGCENT;
this.numeroSequencia = numeroSequencia;
this.integradora = integradora;
}
#Override
public void execute(Connection conn) throws SQLException {
try (CallableStatement stmt = conn
.prepareCall("{CALL APURARCAMPANHASBRINDES.PROC_APURARCAMPANHA(?1, ?2, ?3, ?4, ?5, ?6, ?7)}")) {
stmt.setLong(1, numeroPedido);
stmt.setString(2, codigoFilialNF);
stmt.setString(3, cgcEntCGCENT);
stmt.setLong(4, numeroSequencia);
stmt.setString(5, integradora);
stmt.registerOutParameter(6, Types.VARCHAR);
stmt.registerOutParameter(7, Types.VARCHAR);
stmt.executeUpdate();
mensagem = stmt.getString(6);
geroubrinde = stmt.getString(7);
if (stmt.wasNull()) {
geroubrinde = null;
mensagem = null;
}
}
}
public String getMensagem() {
return mensagem;
}
public String getGeroubrinde() {
return geroubrinde;
}
}
}
If you can switch to JPA 2.1 (and I strongly suggest you to do so) you can simply do:
StoredProcedureQuery storedProcedure = em.createStoredProcedureQuery("yourStoredprocedure");
// set parameters
storedProcedure.registerStoredProcedureParameter("parameterName", String.class, ParameterMode.IN);
storedProcedure.setParameter("parameterName", "yourParameter");
// execute stored procedure
storedProcedure.execute();
otherwise it's a bit more convoluted, simply follow this tutorial.

How to extract path variable from responseentity in Junit testing

Searched but unfortunately I do not get similar questions. I've pasted my involved codes. It uses Spring DATA framework.
Entity EscalationPolicy with ID automatically generated
controller to hand POST request to create an new policy
update JUnit Test
What I'm trying to do in the test is that first create one new EscalationPolicy with the object set by initTest(). Then fetch and update it. However the ID is unknown and I suppose I need to extract it from the return URI. I don't know how to do it after Mockmvc perform and appreciate any help. Thanks!
#Entity
#Table(name = "T_ESCALATIONPOLICY")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class EscalationPolicy implements Serializable {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid")
private String id;
#Column(name = "policy_name")
private String policy_name;
...
}
#RestController
#RequestMapping("/api")
public class EscalationPolicyResource {
...
/**
* POST /escalationPolicys -> Create a new escalationPolicy.
*/
#RequestMapping(value = "/escalationPolicys",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Void> create(#RequestBody EscalationPolicy escalationPolicy) throws URISyntaxException {
log.debug("REST request to save EscalationPolicy : {}", escalationPolicy);
if (escalationPolicy.getId() != null) {
return ResponseEntity.badRequest().header("Failure", "A new escalationPolicy cannot already have an ID").build();
}
escalationPolicyRepository.saveAndFlush(escalationPolicy);
return ResponseEntity.created(new URI("/api/escalationPolicys/" + escalationPolicy.getId())).build();
}
...
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
public class EscalationPolicyResourceTest {
#Before
public void initTest() {
escalationPolicy = new EscalationPolicy();
escalationPolicy.setPolicy_name("Policy Test");
...
}
#Test
#Transactional
public void updatePolicy() throws Exception {
// Create the EscalationPolicy
restEscalationPolicyMockMvc.perform(post("/api/escalationPolicys")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(escalationPolicy)))
.andExpect(status().isCreated());
// Get the created policy
EscalationPolicy e = escalationPolicyRepository.findOne(id);
~~need ID here
}
...
}
Though it may not be the most elegant way to deal with it, I think a way to bypass the problem. I save the id in the header map and in the test code to extract it.
#RestController
#RequestMapping("/api")
public class EscalationPolicyResource {
...
/**
* POST /escalationPolicys -> Create a new escalationPolicy.
*/
#RequestMapping(value = "/escalationPolicys",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
#Timed
public ResponseEntity<Void> create(#RequestBody EscalationPolicy escalationPolicy) throws URISyntaxException {
log.debug("REST request to save EscalationPolicy : {}", escalationPolicy);
if (escalationPolicy.getId() != null) {
return ResponseEntity.badRequest().header("Failure", "A new escalationPolicy cannot already have an ID").build();
}
escalationPolicyRepository.saveAndFlush(escalationPolicy);
HttpHeaders headers = new HttpHeaders();
headers.set("policyID", escalationPolicy.getId());
return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
}
...
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest
public class EscalationPolicyResourceTest {
#Before
public void initTest() {
escalationPolicy = new EscalationPolicy();
escalationPolicy.setPolicy_name("Policy Test");
...
}
#Test
#Transactional
public void updatePolicy() throws Exception {
// Create the EscalationPolicy
ResultActions action =
restEscalationPolicyMockMvc.perform(post("/api/escalationPolicys")
.contentType(TestUtil.APPLICATION_JSON_UTF8)
.content(TestUtil.convertObjectToJsonBytes(escalationPolicy)));
action.andExpect(status().isCreated());
id = (String)action.andReturn().getResponse().getHeaderValue("policyID");
// Get the created policy
EscalationPolicy e = escalationPolicyRepository.findOne(id);
}
...
}