I have a problem with Orika 1.4.5 and PermGen Space.
Indeed, i'm using a a ConfigurableMapper this way :
public class SoapSearchPrdvFreeSlotsMapper extends ConfigurableMapper {
#Override
public void configure(MapperFactory mapperFactory) {
mapperFactory.registerClassMap(mapperFactory.classMap(PrdvFreeSlot.class, PrdvWsListerDispoTelV2Filter.class)
.field("typeRdv", "wsldtTypeRdv")
.field("motifId", "wsldtMotifId")
.byDefault().toClassMap());
}
mapperFactory.registerClassMap(mapperFactory.classMap(PrdvFreeSlot.class, PrdvWsListerDispoTelV2.class)
.field("typeRdv", "wsldtTypeRdv")
.field("motifId", "wsldtMotifId")
.field("quantum", "wsldtActiviteIdActivQuantum")
.field("activiteJours", "wsldtActiviteIdActivJours")
.field("activiteHeureFerme", "wsldtActiviteIdActivHeureFerme")
.field("activiteHeureOuvert", "wsldtActiviteIdActivHeureOuvert")
.field("startDate", "disDate")
.field("disCapacity", "disCapacite")
.field("disReserve", "disReserve")
.field("reserveCC", "wsldtReserveCC")
.byDefault().toClassMap());
}
}
#Override
public void configureFactoryBuilder(DefaultMapperFactory.Builder builder) {
builder.build().getConverterFactory().registerConverter(new DateXmlDateConverter());
}
}
But each time i call this mapper, i have autogenerated class mappers which are stored in the PermGen.
I try to use the "existsRegisteredMapper" of the MapperFactory to prevent class mappers auto-generation but it doesn't work:
public static <T, U> boolean existsRegisteredMapperInFactory(MapperFactory mapperFactory, Class<T> classSrc, Class<U> classDest) {
return mapperFactory.existsRegisteredMapper(TypeFactory.valueOf(classSrc), TypeFactory.valueOf(classDest), true);
}
and the modified first code block:
if (!existsRegisteredMapperInFactory(mapperFactory, PrdvWsListerDispoTelV2Filter.class, PrdvFreeSlot.class)) {
mapperFactory.registerClassMap(mapperFactory.classMap(PrdvFreeSlot.class, PrdvWsListerDispoTelV2Filter.class)
.field("typeRdv", "wsldtTypeRdv")
.field("motifId", "wsldtMotifId")
.byDefault().toClassMap());
}
Please, Is there a way to prevent class mappers autogeneration without rewriting all the mappers i have ?
Thanks for your help.
Please make sure that the mapper is a singleton. You don't need to instantiate it everytime.
You don't need to verify if the the mapper has been registered or not. It will be generated only once (per MapperFactory instance).
So just make sure that SoapSearchPrdvFreeSlotsMapper is a singleton (only one instance, ConfigurableMapper is thread-safe)
Related
I'm writing a spring batch job and in one of my step I have the following code for the processor:
#Component
public class SubscriberProcessor implements ItemProcessor<NewsletterSubscriber, Account>, InitializingBean {
#Autowired
private AccountService service;
#Override public Account process(NewsletterSubscriber item) throws Exception {
if (!Strings.isNullOrEmpty(item.getId())) {
return service.getAccount(item.getId());
}
// search with email address
List<Account> accounts = service.findByEmail(item.getEmail());
checkState(accounts.size() <= 1, "Found more than one account with email %s", item.getEmail());
return accounts.isEmpty() ? null : accounts.get(0);
}
#Override public void afterPropertiesSet() throws Exception {
Assert.notNull(service, "account service must be set");
}
}
The above code works but I've found out that there are some edge cases where having more than one Account per NewsletterSubscriber is allowed. So I need to remove the state check and to pass more than one Account to the item writer.
One solution I found is to change both ItemProcessor and ItemWriter to deal with List<Account> type instead of Account but this have two drawbacks:
Code and tests are uglier and harder to write and maintain because of nested lists in writer
Most important more than one Account object may be written in the same transaction because a list given to writer may contain multiple accounts and I'd like to avoid this.
Is there any way, maybe using a listener, or replacing some internal component used by spring batch to avoid lists in processor?
Update
I've opened an issue on spring Jira for this problem.
I'm looking into isComplete and getAdjustedOutputs methods in FaultTolerantChunkProcessor which are marked as extension points in SimpleChunkProcessor to see if I can use them in some way to achieve my goal.
Any hint is welcome.
Item Processor takes one thing in, and returns a list
MyItemProcessor implements ItemProcessor<SingleThing,List<ExtractedThingFromSingleThing>> {
public List<ExtractedThingFromSingleThing> process(SingleThing thing) {
//parse and convert to list
}
}
Wrap the downstream writer to iron things out. This way stuff downstream from this writer doesn't have to work with lists.
#StepScope
public class ItemListWriter<T> implements ItemWriter<List<T>> {
private ItemWriter<T> wrapped;
public ItemListWriter(ItemWriter<T> wrapped) {
this.wrapped = wrapped;
}
#Override
public void write(List<? extends List<T>> items) throws Exception {
for (List<T> subList : items) {
wrapped.write(subList);
}
}
}
There isn't a way to return more than one item per call to an ItemProcessor in Spring Batch without getting pretty far into the weeds. If you really want to know where the relationship between an ItemProcessor and ItemWriter exits (not recommended), take a look at the implementations of the ChunkProcessor interface. While the simple case (SimpleChunkProcessor) isn't that bad, if you use any of the fault tolerant logic (skip/retry via FaultTolerantChunkProcessor), it get's very unwieldily quick.
A much simpler option would be to move this logic to an ItemReader that does this enrichment before returning the item. Wrap whatever ItemReader you're using in a custom ItemReader implementation that does the service lookup before returning the item. In this case, instead of returning a NewsletterSubscriber from the reader, you'd be returning an Account based on the previous information.
Instead of returning an Account you return create an AccountWrapper or Collection. The Writer obviously must take this into account :)
You can made transformer to transform your Pojo( Pojo object from file) to your Entity
By making the following code :
public class Intializer {
public static LGInfo initializeEntity() throws Exception {
Constructor<LGInfo> constr1 = LGInfo.class.getConstructor();
LGInfo info = constr1.newInstance();
return info;
}
}
And in your item Processor
public class LgItemProcessor<LgBulkLine, LGInfo> implements ItemProcessor<LgBulkLine, LGInfo> {
private static final Log log = LogFactory.getLog(LgItemProcessor.class);
#SuppressWarnings("unchecked")
#Override
public LGInfo process(LgBulkLine item) throws Exception {
log.info(item);
return (LGInfo) Intializer.initializeEntity();
}
}
I am doing a Spring project for the first time and am stuck with a problem.
I have a java class:
#Component
#Conditional(AppA.class)
public class AppDeploy {...}
Now I need to modify this like:
#Component
#Conditional(AppA.class or AppB.class)
public class AppDeploy {...}
Can someone help me with how to do this?
Thanks in anticipation.
You can create your own conditional annotation which enables you to provide parameters and then you can apply the tests conditions depending on the provided parameter value:
see this post for more details: http://www.javacodegeeks.com/2013/10/spring-4-conditional.html
It was very simple, Should have taken a little time before posting the question.
Here is how I did it.
Created a new Class:
public class AppAOrB implements Condition {
public AppAOrB() {
super();
}
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment env = conditionContext.getEnvironment();
return env.containsProperty("APP_A")||env.containsProperty("APP_B");
}
}
Then used it like:
#Component
#Conditional(AppAOrB.class)
public class AppDeploy {...}
I have a slightly different approach.
From your code, I can conclude(Maybe I am wrong) that You have already implemented conditions AppA.class and AppB.class and You wonder how to implement the AppAOrB.class condition in an elegant way. When You take into account that AppA.class and AppB.class are just regular java classes, then implementation is obvious:
public class AppAOrB implements Condition {
#Override
public boolean matches(#NonNull ConditionContext context, #NonNull AnnotatedTypeMetadata metadata) {
return new AppA().matches(context, metadata) || new AppB().matches(context, metadata);
}
}
The pros of this approach is that it follows the DRY rule.
Suppose I have a validation annotation on my Interface method to validate input arguments and return value.
Is it possible at the moment (V 1.9.5) to tell Mockito to invoke this validator during the invocation process?
The background would be to prevent developers from writing unrealistic tests by mocking the given interface in a way that violates the specified validator.
So what I would want is to register something like
class MyAnswerInterceptor<T> implements AnswerInterceptor<T> {
#Override
public Answer<T> intercept(final Answer<T> answer) {
return new Answer<T>() {
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
validateArguments(invocation);
T result = answer.answer(invocation);
validateReturnValue(result);
return result;
}
}
}
}
to be called on every answer of a given mock.
Is this possible at all? I've looked into the code, also to check if I could hack in at some point (even using reflection or the like), but it seems due to entanglement of instance creation and logic, it's hardly possible to achieve what I want (i.e. stuff like MockHandler mockHandler = new MockHandlerFactory().create(settings); makes it impossible to hook in and put custom stuff on top without patching and deploying the whole thing...)
Any insight would be highly appreciated :-)
You could achieve that by creating a custom MockMaker.
MockMaker is an extension point that makes it possible to use custom dynamic proxies and avoid using the default cglib/asm/objenesis implementation
Our custom implementation delegates all the complex stuff to the default MockMaker: CglibMockMaker. It "decorates" only the createMock method by registering on the settings parameter an InvocationListener. This listener will be notified when an invocation have been done allowing use to call validateArguments and validateReturnValue.
import org.mockito.internal.creation.CglibMockMaker;
import org.mockito.invocation.Invocation;
import org.mockito.invocation.MockHandler;
import org.mockito.listeners.InvocationListener;
import org.mockito.listeners.MethodInvocationReport;
import org.mockito.mock.MockCreationSettings;
import org.mockito.plugins.MockMaker;
public class ValidationMockMaker implements MockMaker {
private final MockMaker delegate = new CglibMockMaker();
public ValidationMockMaker() {
}
#Override
public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) {
settings.getInvocationListeners().add(new InvocationListener() {
#Override
public void reportInvocation(MethodInvocationReport methodInvocationReport) {
Invocation invocation = (Invocation) methodInvocationReport.getInvocation();
validateArguments(invocation.getArguments());
validateReturnValue(methodInvocationReport.getReturnedValue());
}
});
return delegate.createMock(settings, handler);
}
#Override
public MockHandler getHandler(Object mock) {
return delegate.getHandler(mock);
}
#Override
public void resetMock(Object mock, MockHandler newHandler, MockCreationSettings settings) {
delegate.resetMock(mock, newHandler, settings);
}
protected void validateArguments(Object... arguments) {
// Arrays.stream(arguments).forEach(Objects::requireNonNull);
}
private void validateReturnValue(Object result) {
// Objects.requireNonNull(result);
}
}
Last but not least, we need to tell to Mockito to use our implementation. This is possible by adding a file
mockito-extensions/org.mockito.plugins.MockMaker
containing our MockMaker class name:
ValidationMockMaker
See Using the extension point section in the javadoc.
this is really confusing! if you use a JsonGeneratorDelegate as-is it doesn't transmit calls to setPrettyPrinter() to the delegate
Probably just an oversight -- feel free to file an issue to get this corrected for future versions. Delegate is supposed to delegate all calls by default.
So what is your real question? You can always define your own enhanced JsonGeneratorDelegate, like this:
public class PrettyPrintJsonGeneratorDelegate extends JsonGeneratorDelegate {
public PrettyPrintJsonGeneratorDelegate (final JsonGenerator delegate) {
super (delegate);
}
#Override
public JsonGenerator setPrettyPrinter(final PrettyPrinter pp) {
delegate.setPrettyPrinter (pp);
return this;
}
}
I want to declare a warning on all fields Annotated with #org.jboss.weld.context.ejb.Ejb in AspectJ.
But I do not find a way how to select that field.
I guess the aspect should be something like that:
public aspect WrongEjbAnnotationWarningAspect {
declare warning :
within(com.queomedia..*) &&
??? (#org.jboss.weld.context.ejb.Ejb)
: "WrongEjbAnnotationErrorAspect: use javax.ejb.EJB instead of weld Ejb!";
}
Or is it impossible to declare warnings on fields at all?
The only field pointcuts I see are for get and set. This makes sense because aspects are primarily about executing code. Declaring compiler warnings is sortof a nice side benefit. If we just talk about a field, independent of the use of that field, when would the pointcut be hit? I think you should be able to do what you want with the Annotation Processing Tool instead of AspectJ. Here is a first stab at it, mostly copied from the example on the tool's web page linked above.
public class EmitWarningsForEjbAnnotations implements AnnotationProcessorFactory {
// Process any set of annotations
private static final Collection<String> supportedAnnotations
= unmodifiableCollection(Arrays.asList("*"));
// No supported options
private static final Collection<String> supportedOptions = emptySet();
public Collection<String> supportedAnnotationTypes() {
return supportedAnnotations;
}
public Collection<String> supportedOptions() {
return supportedOptions;
}
public AnnotationProcessor getProcessorFor(
Set<AnnotationTypeDeclaration> atds,
AnnotationProcessorEnvironment env) {
return new EjbAnnotationProcessor(env);
}
private static class EjbAnnotationProcessor implements AnnotationProcessor {
private final AnnotationProcessorEnvironment env;
EjbAnnotationProcessor(AnnotationProcessorEnvironment env) {
this.env = env;
}
public void process() {
for (TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations())
typeDecl.accept(new ListClassVisitor());
}
private static class ListClassVisitor extends SimpleDeclarationVisitor {
public void visitClassDeclaration(ClassDeclaration d) {
for (FieldDeclaration fd : d.getFields()) {
fd.getAnnotation(org.jboss.weld.context.ejb.Ejb.class);
}
}
}
}
}
Sort of agree with #JohnWatts, but also feel that get() will work for you:
declare warning :
within(com.queomedia..*) &&
get(#org.jboss.weld.context.ejb.Ejb * *.*)
: "WrongEjbAnnotationErrorAspect: use javax.ejb.EJB instead of weld Ejb!";
This will show a warning at any code that tries to use the fields annotated with #org.jboss.weld.context.ejb.Ejb and not the field itself, but should suffice as a compile time warning?