Configure 2 different MessageConverters for 2 Controllers - json

I would like to configure two different HttpMessageConverters having the same MediaType for two separate controllers. The reason is that there are some external services that uses different JSON formats. We are not able to change them.
Is it possible? Can I create two WebMvcConfigurerAdapters and split the traffic somehow? If possible, is it a good practice?

Finally, I solved the problem by overriding MessageConverter adding possiblity to configure its jaxbcontext and assign supported packages. So, then I can create 2 different MesssageConverters for the same controller and depending on a return class use one or another.
public class MoxyMessageConverter extends AbstractHttpMessageConverter<Object> {
private final JAXBContext jAXBContext;
private String[] supportedPackages = { ... }; // some defaults
public MoxyMessageConverter(JAXBContext jAXBContext) {
this.jAXBContext = jAXBContext;
}
public String[] getSupportedPackages() {
return supportedPackages;
}
public void setSupportedPackages(String[] supportedPackages) {
this.supportedPackages = supportedPackages;
}
#Override
protected boolean supports(Class<?> clazz) {
String packageName = clazz.getPackage().getName();
for (String supportedPackage : supportedPackages) {
if (packageName.startsWith(supportedPackage))
return true;
}
return false;
}
#Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
..
}
#Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
..
}
}
and in the #Configuration class:
#Configuration
#EnableWebMvc
#EnableTransactionManagement
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
super.extendMessageConverters(converters);
MoxyMessageConverter defaultMessageConverter = new MoxyMessageConverter(defaultJAXBContext);
defaultMessageConverter.setSupportedPackages(new String[] { "xxx.xxx.xxx.webservices" });
converters.add(0, defaultMessageConverter );
MoxyMessageConverter payUMessageConverter = new MoxyMessageConverter(payUJAXBContext);
payUMessageConverter.setSupportedPackages(new String[] { "xxx.xxx.xxx.webservices.payu" });
converters.add(0, payUMessageConverter);
}
}

Related

I need to write JUNIT for Apache camel route

I have camel route as below
public class IncomingBatchFileRoute extends RouteBuilder {
#Value(CCS_PROCESSING_INCOMING_DIRECTORY)
private String source;
#Override
public void configure() throws Exception {
from(sourceLocation)).autoStartup(false).to("encryptionEndPoint");
}
}
I need to write a JUNIT For above camel route and am new to it and created a structure as below
public class IncomingBatchFileRouteTest extends CamelTestSupport{
#Override
public RoutesBuilder createRouteBuilder() throws Exception {
return new IncomingBatchFileRoute();
}
#Test
public void sampleMockTest() {
}
}
Not sure how to complete it. Request you to help me on this
You need to mock your encryptionEndPoint and start your route with a producerTemplate
#Produce(uri = CCS_PROCESSING_INCOMING_DIRECTORY)
protected ProducerTemplate template;
#EndpointInject(uri = "encryptionEndPoint")
protected MockEndpoint resultEndpoint;
#Test
public void sampleMockTest() {
// GIVEN
this.resultEndpoint.expectedMessageCount(1);
// WHEN
this.template.sendBody("Hey");
// THEN
this.resultEndpoint.assertIsSatisfied();
}

Lazy collection in Spring JPA with Jackson and elasticsearch wihtout jsonignore

We have spring boot with elasticsearch and mysql. We have a feature for reindexing all data from the mysql into elasticsearch, which is simple as:
#Service
#Transactional
public class SearchIndexer {
public void reindex(){
elasticsearchRepository.save(jpaRepository.findAll());
}
}
Now we have an entity called invoice, which has a lazy loaded collection with a "derived" calculation:
#Entity
#Table(name = "invoice")
#Document(indexName = "invoice")
public class Invoice implements Serializable {
//... other props
#OneToMany(fetch = FetchType.LAZY, mappedBy = "invoice")
#JsonIgnore
private Set<InvoiceItem> invoiceItems = new LinkedHashSet<>();
// getter and setters for invoiceItems
public boolean isAllSimple() {
if(getInvoiceType()==null){
return false;
}
if(getInvoiceItems()==null){
return false;
}
for(InvoiceItem item : getInvoiceItems()){
if(!item.isSimple()){
return false;
}
}
return true;
}
}
When the rest-controller is used, the resulting json contains correctly a property "allSimple". This is, because we run that with hibernate5module in one transaction.
However, when we call elasticsearchRepository.save(jpaRepository.findAll()) (also in a transaction), the objectmapper for elasticsearch cannot serialize the "allSimple" property, beacause of a LazyInitializationException. The elasticsearch-objectmapper is configured as follows:
#Bean
public ElasticsearchTemplate elasticsearchTemplate(Client client, Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder, Hibernate5Module hibernate5Module) {
return new ElasticsearchTemplate(client, new CustomEntityMapper(jackson2ObjectMapperBuilder.createXmlMapper(false).modulesToInstall(hibernate5Module).build()));
}
public class CustomEntityMapper implements EntityMapper {
private ObjectMapper objectMapper;
public CustomEntityMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
objectMapper.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure( DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
}
#Override
public String mapToString(Object object) throws IOException {
return objectMapper.writeValueAsString(object);
}
#Override
public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
return objectMapper.readValue(source, clazz);
}
}
The hibernate5module is loaded and registered, but did not solve the problem.
Normally we would add a "JsonIgnore" to that property, but we need that value, so this is no option.
Any ideas?!
I had a project configurated with this.
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = "com.sagasoftware.tracker.*")
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
Hibernate5Module hibernate5Module = new Hibernate5Module();
objectMapper.registerModule(hibernate5Module);
objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
messageConverter.setObjectMapper(objectMapper);
return messageConverter;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(mappingJackson2HttpMessageConverter());
super.configureMessageConverters(converters);
}
}
If you are using spring boot, declaring the bean MappingJackson2HttpMessageConverter and registering the hibernate5module should fix your problem.
I could render a entity throught a rest controller.

Test play controller with session data

I have a simple controller test.
route(fakeRequest(routes.Accounts.accounts()).session("sessionref","fakeSession"));
Secured Autheticator looks like this:
public class Secured extends play.mvc.Security.Authenticator {
#Inject
AuthServices authService;
public String getUsername(Http.Context context) {
return authService.checkSession(context);
}
#Override
public Result onUnauthorized(Http.Context context) {
return ok(index.render(formFactory.form(forms.LoginForm.class)));
}
}
How can i mock authService?
I tried to mock with guice bind but this method don't work
#Before
public void setup() {
startPlay();
MockitoAnnotations.initMocks(this);
Module testModule = new AbstractModule() {
#Override
public void configure() {
bind(AuthServices.class)
.toInstance(authServices);
}
};
GuiceApplicationBuilder builder = new GuiceApplicationLoader()
.builder(new play.ApplicationLoader.Context(Environment.simple()))
.in(Mode.TEST)
.overrides(testModule);
Guice.createInjector(builder.applicationModule()).injectMembers(this);
}
You can read this for testing Play controllers and follow this example for testing with Guice.
For your case it is something like this:
public class MyTest extends WithApplication {
#Mock
AuthServices mockAuthService;
#Override
protected Application provideApplication() {
return new GuiceApplicationBuilder()
.overrides(bind(CacheProvider.class).toInstance(mockAuthService))
.in(Mode.TEST)
.build();
}
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testAccounts() {
running(provideApplication(), () -> {
RequestBuilder testRequest = Helpers.fakeRequest(controllers.routes.Accounts.accounts()).session("sessionref","fakeSession");
Result result = route(testRequest);
//assert here the expected result
});
}
}

How to add insert query in spring mvc + hibernate project

My hibernate configuration class include following code
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
return properties;
}
My package structures like this enter code here
My daoImpl class like this.
#Repository("passArrayDao")
public class PassArrayDaoImpl extends AbstractDao<Integer, Arr> implements PassArrayDao {
#Override
public void passarray(Arr arr) {
}
}
normally we user hibernate for insert update delete data no.
#Override
public Book findBookById(int id) {
return bookDao.findBookById(id);
}
#Override
public List<Book> getAllBooks() {
return bookDao.getAllBooks();
}
#Override
public List<Book> findBooksByTitle(String title) {
return bookDao.findBooksByTitle(title);
}
#Override
public void deleteBookById(int id) {
bookDao.deleteBookById(id);
}
#Override
public void updateBook(Book book) {
bookDao.updateBook(book);
}
bus now i want write insert query into daoImpl class. How I create it.

spring batch - how to pass dynamic list while application running to ListItemReader store it into database

I'm new to this Spring-Batch technology please help regarding how to pass dynamic list while application running to ListItemReader and store it to MySql DB.
Ex. I fetch some value from DB and do some calculation on that fetched data and i prepare one list and this new list to be pass to ListItemReader and store it into DB.
Thank you for the help.
Below are custom implementations of ListItemWriter and ListItemReader which lets you define a name property. This property is used as a key to store the list in the JobExecutionContext.
In your case, you can have 3 steps :
JDBCReader > ListItemWriter
Calculation Tasklet
ListItemReader > JDBCWriter
If your tasklet needs to get the lists, you can use the same way as below (ie. read/write the JobExecutionContext).
The reader :
public class CustomListItemReader<T> implements ItemReader<T>, StepExecutionListener {
private String name;
private List<T> list;
#Override
public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
if (list != null && !list.isEmpty()) {
return list.remove(0);
}
return null;
}
#Override
public void beforeStep(StepExecution stepExecution) {
list = (List<T>) stepExecution.getJobExecution().getExecutionContext().get(name);
}
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
return null;
}
public void setName(String name) {
this.name = name;
}
}
The writer :
public class CustomListItemWriter<T> implements ItemWriter<T>, StepExecutionListener {
private String name;
private List<T> list = new ArrayList<T>();
#Override
public void write(List<? extends T> items) throws Exception {
for (T item : items) {
list.add(item);
}
}
#Override
public void beforeStep(StepExecution stepExecution) {}
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
stepExecution.getJobExecution().getExecutionContext().put(name, list);
return null;
}
public void setName(String name) {
this.name = name;
}
}