How to configure json format when using jaxb annotations with jersey - jaxb

I am using jersey to expose a service which uses jaxb annotated classes to configure the look of the json.
I am trying to include the type directive in each json element. I do this by providing a Provider as such:
import org.codehaus.jackson.JsonParser.Feature;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.ObjectMapper.DefaultTyping;
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class CmsContextResolver implements ContextResolver<ObjectMapper> {
ObjectMapper mapper;
public CmsContextResolver() {
mapper = new ObjectMapper();
// #JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include =
// JsonTypeInfo.As.WRAPPER_OBJECT, property = "#type")
mapper.configure(Feature.INTERN_FIELD_NAMES, true);
mapper.enableDefaultTypingAsProperty(DefaultTyping.NON_FINAL, "#type");
}
#Override
public ObjectMapper getContext(Class<?> arg0) {
return mapper;
}
}
And this provider is definitely being picked up.
10 May 2011 3:53:18 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
INFO: Provider classes found:
class com.afrozaar.cms.service.CmsContextResolver
But it is making no difference. The format of the json is unaffected.
As far as I can tell the problem stems from the fact that jersey is not using jackson to serialize? or that jersey is ignoring my jackson configuration overrides...

I don't know why your code isn't working, but this is what I use:
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider;
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class JsonProvider extends JacksonJaxbJsonProvider {
public JsonProvider() {
super();
setMapper( myConfiguredObjectMapper );
}

Related

Is there a way to pass list of enums to step in cucumber 4.x and java

let's say I have example enum class
public enum Name { FIRST_NAME, LAST_NAME;}
and I have a such step
Then followed name types are listed:
| FIRST_NAME |
| LAST_NAME |
in which I want to pass List like
#Then("^followed name types are listed:$")
public void followedNameTypesAreListed(List<Name> nameTypes){...}
I'm currently migrating to cucumber 4.x and what i figured out is that i can register custom DataTableType like
typreRegistry.defineDataTableType(new DataTableType(Name.class,
(TableCellTransformer<Name>) Name::valueOf)
but doing it for every single enum class doesn't sound very efficient, isn't there any other way to handle list for any enum class?
One quick way to do this would be to us an object mapper as the default cell transformer. The object mapper will then be used in all situations where a cell is mapped to a single object and no existing data table type has been defined.
You could use jackson-databind for this.
In Cucumber v4:
package com.example.app;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cucumber.core.api.TypeRegistry;
import io.cucumber.core.api.TypeRegistryConfigurer;
import java.util.Locale;
public class ParameterTypes implements TypeRegistryConfigurer {
private final ObjectMapper objectMapper = new ObjectMapper();
#Override
public Locale locale() {
return Locale.ENGLISH;
}
#Override
public void configureTypeRegistry(TypeRegistry typeRegistry) {
typeRegistry.setDefaultDataTableCellTransformer(objectMapper::convertValue);
}
}
And in v5:
package com.example.app;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cucumber.java.DefaultDataTableCellTransformer;
import java.lang.reflect.Type;
public class DataTableSteps {
private final ObjectMapper objectMapper = new ObjectMapper();
#DefaultDataTableCellTransformer
public Object defaultTransformer(Object fromValue, Type toValueType) {
return objectMapper.convertValue(fromValue, objectMapper.constructType(toValueType));
}
}

Injecting a different bean during local development with Quarkus

With Spring and Micronaut, there are very concise ways to inject a different bean depending on what environment/profile an application is running in. I'm trying to do the same with Quarkus.
I've read this post: https://quarkus.io/blog/quarkus-dependency-injection/. And the process is alluded to in this StackOverflow post: How can I override a CDI bean in Quarkus for testing?. That last post says, "create bean in test directory".
My problem is slightly different. I'd like to inject a bean when in "development". In production, I'd like the default bean injected. From the docs, I can't see a way to have the app make this distinction.
If I have a default class like this:
#DefaultBean
#ApplicationScoped
class ProdProvider : SomeProvider {}
And I want to override it like this:
#Alternative
#Priority(1)
class DevProvider : SomeProvider {}
How can I make this happen only in dev mode?
In one case, I have a credential provider class that sets up Google's PubSub emulator while in local development. In production, I use a class that implements the same interface, but a real credential provider. The particular case that led me to asking this question, though is a a class that implements one method:
#ApplicationScoped
class VaultLoginJwtProvider : LoginJwtProvider {
#ConfigProperty(name = "vault.tokenPath")
private val jwtPath: String? = null
companion object {
val logger: Logger = LoggerFactory.getLogger("VaultTokenProvider")
}
override fun getLoginJwt(): Optional<String> {
logger.info("Using Vault Login JWT")
return try {
Optional.of(String(Files.readAllBytes(Paths.get(jwtPath))).trim { it <= ' ' })
} catch (e: Exception) {
logger.error("Could not read vault token at $jwtPath")
logger.error(e.printStackTrace().toString())
Optional.empty()
}
}
}
That class is injected into another class via constructor injection:
#Singleton
class JwtServiceImpl(
#RestClient val vaultClient: VaultClient,
#Inject val loginJwtProvider: LoginJwtProvider
) {
private var serviceJwt: String? = null
companion object {
val logger: Logger = LoggerFactory.getLogger("JwtServiceImpl")
}
private fun getLoginToken(): String? {
val vaultLogin = VaultLogin(
role = "user-service",
jwt = loginJwtProvider.getLoginJwt().get()
)
val loginResponse = vaultClient.login(vaultLogin)
return loginResponse.auth.clientToken
}
}
I'd like to inject more of a "mock" class while in development that just returns a static string. I could use ProfileManager.getActiveProfile(), but that has me mixing development concerns into my logic. And I don't feel that that has any place in my compiled production code.
This is possible in Micronaut by using the annotation #Requires(env = ["dev", "test"]). I did briefly look at using #Produces but the Oracle EE docs seemed a little bit difficult for me to grasp. If that's the solution, I'll dig in.
In case anybody else comes across this, this is how to do it: https://quarkus.io/guides/cdi-reference#enabling-beans-for-quarkus-build-profile
For example:
import javax.enterprise.inject.Produces;
import com.oi1p.common.EmailSender;
import com.oi1p.common.ErrorEmailSender;
import com.oi1p.common.LogOnlyEmailSender;
import io.quarkus.arc.DefaultBean;
import io.quarkus.arc.profile.IfBuildProfile;
#ApplicationScoped
public class Producers {
#Produces
#IfBuildProfile("dev")
public EmailSender logOnlyEmailSender() {
return new LogOnlyEmailSender();
}
#Produces
#DefaultBean
public EmailSender errorEmailSender() {
// TODO: implement a real email sender. This one explodes when poked.
return new ErrorEmailSender();
}
}
My solution is to create the final bean on my own inside a #javax.ws.rs.ext.Provider. Not as elegant as Micronaut #Requires, but well, it works.
Note that instance of SomeProvider is not a "bean", you have to care for the lifecycle on your own (dependency injection, PostConstruct, no PreDestroy, ...).
org.acme.SomeProvider.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
public interface SomeProvider {
void providerMethod();
#ApplicationScoped
class ProdProviderRequirement {
void foo() {}
}
class ProdProvider implements SomeProvider {
private final ProdProviderRequirement prodProviderRequirement;
ProdProvider(final ProdProviderRequirement prodProviderRequirement) {
this.prodProviderRequirement = prodProviderRequirement;
}
#Override
public void providerMethod() {
prodProviderRequirement.foo();
}
}
class DevProvider implements SomeProvider {
#Override
public void providerMethod() {}
}
}
org.acme.SomeProviderFactory.java
package org.acme;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Inject;
import javax.ws.rs.ext.Provider;
import org.acme.SomeProvider.DevProvider;
import org.acme.SomeProvider.ProdProvider;
import org.acme.SomeProvider.ProdProviderRequirement;
#Provider
class SomeProviderFactory {
SomeProvider someProvider;
#Inject
SomeProviderFactory(final ProdProviderRequirement prodProviderRequirement) {
final var someCondition = true;
someProvider = someCondition ? new DevProvider() : new ProdProvider(prodProviderRequirement);
}
#Produces
#ApplicationScoped
SomeProvider someProvider() {
return someProvider;
}
}

How to override class DefaultScreenNameValidator in liferay 7?

I am trying to override a class DefaultScreenNameValidator that implements ScreenNameValidator interface. For this , I copied the class and put it into another module. One change that I made is in annotation that is as follows:-
#Component(
property = {
"service.ranking:Integer=500"
}
)
I got a successful build using this. But when I tried to deploy the project, I got error as java.lang.NoClassDefFoundError: com/liferay/portal/kernel/security/auth/ScreenNameValidator.Can you suggest me how to eradicate this error. Thanx in advance..
I'm wondering, wouldn't it be better to instead create a module that also implements the ScreenNameValidator interface, and define your custom logic in there? Then you can just simply tell Liferay to use that validator instead of the DefaultScreenNameValidator.
For example, a minimalistic implementation:
import com.liferay.portal.kernel.security.auth.ScreenNameValidator;
import org.osgi.service.component.annotations.Component;
#Component(
immediate = true,
service = ScreenNameValidator.class
)
public class CustomScreenNameValidator implements ScreenNameValidator {
#Override
public boolean validate(long companyId, String screenName) {
// Your custom logic
}
}
make sure you have the dependency to portal-kernel in the build.gradle
dependencies {
compile 'com.liferay.portal:com.liferay.portal.kernel:2.0.0'
I made a screenNameValidator using blade-cli you can see the projet at https://github.com/bruinen/liferay-blade-samples/tree/master/liferay-workspace/modules/blade.screenname.validator
import com.liferay.portal.kernel.security.auth.ScreenNameValidator;
import org.osgi.service.component.annotations.Component;
import java.util.Locale;
#Component(
immediate = true,
property = {"service.ranking:Integer=100"},
service = ScreenNameValidator.class
)
public class CustomScreenNameValidator implements ScreenNameValidator {
#Override
public String getAUIValidatorJS() {
return "function(val) {return !(val.indexOf(\"admin\") !==-1)}";
}
#Override
public String getDescription(Locale locale) {
return "The screenName contains reserved words";
}
#Override
public boolean validate(long companyId, String screenName) {
return !screenName.contains("admin");
}
}

How to use of XmlGregorianCalendar with fromJson and toJson methods of gson?

The theme of my project is to give XML format of data and get Json format using google-gson and I have JAXB generated java POJOs from XML schema in which I have a variable of XMLGregorianCalendar datatype.
I give the following input of XML and get the json format from the gson.toJson() method;
<?xml version="1.0" encoding="UTF-8"?>
<EmpRequest xmlns="http://java.com/Employee">
<EmplIn>
<EmpID>12</EmpID>
<Empname>sara</Empname>
<Designation>SA</Designation>
<DOJ>2002-05-30T09:30:10+06:00</DOJ>
</EmplIn>
</EmpRequest>
But in the output, I got the following.
{"emplIn":{"empID":"12","empname":"sara","designation":"SA","doj":{}}}
I surfed google and got the suggestion of adding in the xml schema and changing the XmlGregorianCalendar datatype with string. But I dont want to achieve it from both the ways.
I mean how to get the proper output with the XmlGregorianCalendar datatype through fromJson and toJson methods of gson?
Thank you so much,
Harish Raj.
Hopefully, This can fix my issue of using google-gson.
(The following should be added in where we create the object of Gson)
Step 1:
Gson gson =
new GsonBuilder().registerTypeAdapter(XMLGregorianCalendar.class,
new XGCalConverter.Serializer()).registerTypeAdapter(XMLGregorianCalendar.class,
new XGCalConverter.Deserializer()).create();
Step 2: And we need to create the XGCalConverter Class as like the following.
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import java.lang.reflect.Type;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
public class XGCalConverter
{
public static class Serializer implements JsonSerializer
{
public Serializer()
{
super();
}
public JsonElement serialize(Object t, Type type,
JsonSerializationContext jsonSerializationContext)
{
XMLGregorianCalendar xgcal=(XMLGregorianCalendar)t;
return new JsonPrimitive(xgcal.toXMLFormat());
}
}
public static class Deserializer implements JsonDeserializer
{
public Object deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext)
{
try
{
return DatatypeFactory.newInstance().newXMLGregorianCalendar(jsonElement.getAsString());
}
catch(Exception ex)
{
ex.printStackTrace();
return null;
}
}
}
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
You could use MOXy to handle both the XML and JSON binding aspects of this use case. As I mentioned in my comment MOXy supports the XMLGregorianCalendar type. The Metadata would look like:
EmpRequest
package forum7725188;
import javax.xml.bind.annotation.*;
#XmlRootElement(name="EmpRequest")
#XmlAccessorType(XmlAccessType.FIELD)
public class EmpRequest {
#XmlElement(name="EmplIn")
private EmplIn emplIn;
}
EmplIn
package forum7725188;
import javax.xml.bind.annotation.*;
import javax.xml.datatype.XMLGregorianCalendar;
#XmlAccessorType(XmlAccessType.FIELD)
public class EmplIn {
#XmlElement(name="EmpID")
private long empId;
#XmlElement(name="Empname")
private String name;
#XmlElement(name="Designation")
private String designation;
#XmlElement(name="DOJ")
private XMLGregorianCalendar doj;
}
package-info
#XmlSchema(namespace="http://java.com/Employee", elementFormDefault=XmlNsForm.QUALIFIED)
#XmlAccessorType(XmlAccessType.FIELD)
package forum7725188;
import javax.xml.bind.annotation.*;
Demo
You can configure the MOXy implementation of Marshaller to output JSON by setting the eclipselink.media-type property to be application/json.
package forum7725188;
import java.io.File;
import javax.xml.bind.*;
import javax.xml.namespace.QName;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(EmpRequest.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum7725188/input.xml");
EmpRequest empRequest = (EmpRequest) unmarshaller.unmarshal(xml);
JAXBElement<EmpRequest> jaxbElement = new JAXBElement<EmpRequest>(new QName(""), EmpRequest.class, empRequest);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty("eclipselink.media-type", "application/json");
marshaller.marshal(jaxbElement, System.out);
}
}
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<EmpRequest xmlns="http://java.com/Employee">
<EmplIn>
<EmpID>12</EmpID>
<Empname>sara</Empname>
<Designation>SA</Designation>
<DOJ>2002-05-30T09:30:10+06:00</DOJ>
</EmplIn>
</EmpRequest>
Output
{"EmplIn" :
{"EmpID" : "12",
"Empname" : "sara",
"Designation" : "SA",
"DOJ" : "2002-05-30T09:30:10+06:00"}}
For More Information
http://blog.bdoughan.com/2011/08/binding-to-json-xml-geocode-example.html
http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html

Spring LDAP Template Usage

Please take a look at the test class below. I am trying to do an LDAP search with Spring LDAP Template. I am able to search and produce a list of entries corresponding to the search criteria without the Spring LDAP template by using the DirContext as shown in the method searchWithoutTemplate(). But when I use a LdapTemplate, I end up with a NPE as shown further below. I am sure I must be missing something. Can someone help please?
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapName;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.DefaultDirObjectFactory;
import org.springframework.ldap.core.support.LdapContextSource;
public class LDAPSearchTest {
//bind params
static String url="ldap://<IP>:<PORT>";
static String userName="cn=Directory Manager";
static String password="password123";
static String bindDN="dc=XXX,dc=com";
//search params
static String base = "ou=StandardUser,ou=XXXCustomers,ou=People,dc=XXX,dc=com";
static String filter = "(objectClass=*)";
static String[] attributeFilter = { "cn", "uid" };
static SearchControls sc = new SearchControls();
public static void main(String[] args) throws Exception {
// sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
sc.setReturningAttributes(attributeFilter);
searchWithTemplate(); //NPE
//searchWithoutTemplate(); //works fine
}
public static void searchWithTemplate() throws Exception {
DefaultDirObjectFactory factory = new DefaultDirObjectFactory();
LdapContextSource cs = new LdapContextSource();
cs.setUrl(url);
cs.setUserDn(userName);
cs.setPassword(password);
cs.setBase(bindDN);
cs.setDirObjectFactory(factory.getClass ());
LdapTemplate template = new LdapTemplate(cs);
template.afterPropertiesSet();
System.out.println((template.search(new LdapName(base), filter, sc,
new AttributesMapper() {
public Object mapFromAttributes(Attributes attrs)
throws NamingException {
System.out.println(attrs);
return attrs.get("uid").get();
}
})));
}
public static void searchWithoutTemplate() throws NamingException{
Hashtable env = new Hashtable(11);
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
//env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, userName);
env.put(Context.SECURITY_CREDENTIALS, password);
DirContext dctx = new InitialDirContext(env);
NamingEnumeration results = dctx.search(base, filter, sc);
while (results.hasMore()) {
SearchResult sr = (SearchResult) results.next();
Attributes attrs = sr.getAttributes();
System.out.println(attrs);
Attribute attr = attrs.get("uid");
}
dctx.close();
}
}
Exception is:
Exception in thread "main" java.lang.NullPointerException
at org.springframework.ldap.core.support.AbstractContextSource.getReadOnlyContext(AbstractContextSource.java:125)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:287)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:237)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:588)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:546)
at LDAPSearchTest.searchWithTemplate(LDAPSearchTest.java:47)
at LDAPSearchTest.main(LDAPSearchTest.java:33)
I am using Spring 2.5.6 and Spring LDAP 1.3.0
A quick scan showed that it's the authenticationSource field of AbstractContextSource that is the culprit. That file includes the following comment on the afterPropertiesSet() method:
/**
* Checks that all necessary data is set and that there is no compatibility
* issues, after which the instance is initialized. Note that you need to
* call this method explicitly after setting all desired properties if using
* the class outside of a Spring Context.
*/
public void afterPropertiesSet() throws Exception {
...
}
That method then goes on to create an appropriate authenticationSource if you haven't provided one.
As your test code above is most definitely not running within a Spring context, and you haven't explicitly set an authenticationSource, I think you need to edit your code as follows:
...
cs.setDirObjectFactory(factory.getClass ());
// Allow Spring to configure the Context Source:
cs.afterPropertiesSet();
LdapTemplate template = new LdapTemplate(cs);

Resources