Jsr250JsonSerializer.java
package org.oxerr.jackson.module.jsr250;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Collection;
import java.util.Collections;
import javax.annotation.security.DenyAll;
import javax.annotation.security.RolesAllowed;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializer;
/**
* Excludes the properties that are {@link DenyAll} or not {@link RolesAllowed}
* from the serialization output.
*/
public class Jsr250JsonSerializer extends BeanSerializer {
private static final long serialVersionUID = 2016100501L;
private transient Logger log = LogManager.getLogger(Jsr250JsonSerializer.class);
public Jsr250JsonSerializer(BeanSerializer serializer) {
super(serializer);
}
/**
* {@inheritDoc}
*/
@Override
protected void serializeFields(Object bean, JsonGenerator gen, SerializerProvider provider)
throws IOException, JsonGenerationException {
final Collection<? extends GrantedAuthority> grantedAuthorities = this
.getGrantedAuthorities();
final BeanPropertyWriter[] props;
if (_filteredProps != null && provider.getActiveView() != null) {
props = _filteredProps;
} else {
props = _props;
}
int i = 0;
try {
for (final int len = props.length; i < len; ++i) {
BeanPropertyWriter prop = props[i];
if (prop != null) { // can have nulls in filtered list
final DenyAll denyAll = prop.getAnnotation(DenyAll.class);
final RolesAllowed rolesAllowed = prop.getAnnotation(RolesAllowed.class);
if (denyAll != null) {
log.trace("DenyAll, ignoring {}.", prop);
} else if (rolesAllowed != null && !this.isAllowed(rolesAllowed.value(), grantedAuthorities)) {
log.trace("RolesAllowed({}), ignoring {}.", rolesAllowed::value, () -> prop);
} else {
prop.serializeAsField(bean, gen, provider);
}
}
}
if (_anyGetterWriter != null) {
_anyGetterWriter.getAndSerialize(bean, gen, provider);
}
} catch (Exception e) {
String name = (i == props.length) ? "[anySetter]" : props[i].getName();
wrapAndThrow(provider, e, bean, name);
} catch (StackOverflowError e) {
/* 04-Sep-2009, tatu: Dealing with this is tricky, since we do not
* have many stack frames to spare... just one or two; can't
* make many calls.
*/
// 10-Dec-2015, tatu: and due to above, avoid "from" method, call ctor directly:
//JsonMappingException mapE = JsonMappingException.from(gen, "Infinite recursion (StackOverflowError)", e);
JsonMappingException mapE = new JsonMappingException("Infinite recursion (StackOverflowError)", e);
String name = (i == props.length) ? "[anySetter]" : props[i].getName();
mapE.prependPath(new JsonMappingException.Reference(bean, name));
throw mapE;
}
}
protected boolean isAllowed(String[] rolesAllowed, Collection<? extends GrantedAuthority> grantedAuthorities) {
for (final String role : rolesAllowed) {
for (final GrantedAuthority grantedAuthority : grantedAuthorities) {
if (role.equals(grantedAuthority.getAuthority())) {
return true;
}
}
}
return false;
}
protected Collection<? extends GrantedAuthority> getGrantedAuthorities() {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return authentication != null ? authentication.getAuthorities() : Collections.emptyList();
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
this.log = LogManager.getLogger(Jsr250JsonSerializer.class);
}
}