mybatis mapping the class which protobuf generated - protocol-buffers

How can I map the result to protobuf class in mybatis mapper? There is no set method in protobuf class. Should I generate the entity class by using newBuilder and build method?

Yes, this is possible. In When you are generating the model classes from your proto file each of them are having a Builder (that extends GeneratedMessageV3.Builder). So in your model definition you can add that, like this example:
#ResultType(MyProto.Builder.class)
This is working in fine when you are using ResultHandler, so there you can invoke the build method, like:
#Override
public void handleResult(ResultContext<? extends GeneratedMessageV3.Builder> resultContext) {
GeneratedMessageV3 proto = resultContext.getResultObject().build();
MyProto myproto = (MyProto)proto;
// do something with myproto
}

There is a trick. Let's say you have defined the following protobuf,
package com.example.protobuf;
message HelloMessage {
string id;
uint32 code;
}
You can have your HelloMapper like this,
<resultMap id="helloMessageMap" type="com.example.protobuf.HelloMessage">
<result column="id" property="id_"/>
<result column="code" property="code_"/>
</resultMap>
<select id="selectHelloMessage" resultMap="helloMessageMap">
select id, code from example
</select>
Please notice that id_ and code_ are used instead of id and code.

Related

Capturing entity information in custom entity listener

I would like a custom entity listener to generate an auto-incremented alias for a few of the entities.
I have implemented one util class in order to generate auto incremented alias for the entities in a distributed environment as follows:
#Component
public class AutoIncrementingIdGenerationUtil {
private final RedisTemplate<String, Object> redisTemplate;
public AutoIncrementingIdGenerationUtil(
RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
public String getNextSequenceNumber(String keyName) {
RedisAtomicLong counter = new RedisAtomicLong(keyName,
Objects.requireNonNull(redisTemplate.getConnectionFactory()));
return counter.incrementAndGet();
}
}
Now, I have several entities in my application, for a FEW OF ENTITIES, I would like to generate the alias.
So I am writing my own custom entity listener as follows:
#Component
public class CustomEntityListener<T> {
private final AutoIncrementingIdGenerationUtil autoIncrementingIdGenerationUtil;
public CustomEntityListener(
AutoIncrementingIdGenerationUtil autoIncrementingIdGenerationUtil) {
this.autoIncrementingIdGenerationUtil = autoIncrementingIdGenerationUtil;
}
#PrePersist
void onPrePersist(Object entity) { <----HERE I WOULD LIKE TO CAST TO CONCRETE ENTITY TYPE,
if(StringUtils.isBlank(entity.getAlias())) {
entity.setAlias(autoIncrementingIdgenerationUtil.getNextSequenceNumber(entity.getEntityType());
}
}
As mentioned above, all of the entities do not have an alias attribute. I am not getting any proper idea regarding how to do this. One bad idea is to use getTEntityype(). But in this case, it would be too many if-else and typecast accordingly, which will not look good. Any better idea regarding how to do it?
Another related question in the same context, if I have an entity having a #PrePersist function already, will the function defined in entity listener override this, OR will both of them run?
Entity listeners cannot be parameterized. Just make the relevant entities implement an interface, e.g. Aliased, with a setAlias() method. You'll then have a single type to cast to.
Also, why use Redis? Doesn't your DB have sequences?

How can I pass multiple parameters and use them?

Hi I'm new to myBatis.
I'm using MyBatis and Spring with mybatis-spring.
How can I pass two different types of objects as parameters, and how can I use their properties in query?
<update id="update" parameterType="A, B"> <!-- ##? -->
UPDATE SOME WHERE x=A.x AND y=B.y <!-- ##? -->
</update>
Do not specify parameterType but use #Param annotation on parameters in mapper:
#Mapper
public interface MyMapper {
void update(#Param("a") A a, #Param("b") B b);
...
}
Then reference them in mapping:
<update id="update" >
UPDATE SOME WHERE x=#{a.x} AND y=#{b.y}
</update>
Use parameterType="map" and #Param annotation.
Method declared in interface:
void mapCategoryAndPage(#Param("categoryLocalId") Long categoryLocalId, #Param("pageLocalId") Long localId);
It is not required that value of #Param annotation must be equal to name of parameter
<insert id="mapCategoryAndPage" parameterType="map">
INSERT INTO
category_page_mapping (
page_local_id,
category_local_id)
VALUES
(#{pageLocalId},
#{categoryLocalId});
</insert>
I would suggest reading the MyBatis documentation - it is pretty comprehensive and accurate.
Lets take an example: updating a customer's name from a com.mycompany.Customer POJO instance, which has a getFirstName() getter.
Pass an instance of your Customer class as the parameter
Set the parameterType= "com.mycompany.Customer". But check out the alias facility - then you can use the shorthand version parameterType="Customer"
Use the standard MyBatis syntax in the SQL: ... set FIRST_NAME = #{firstName}
(Edit) If you need to pass multiple objects there are various options:
Pass a map containing the multiple objects
Create a utility class the aggregates your multiple classes, and pass this as the parameter.
Again, please read the manual...

Freemarker - access static variables of an object

I have a simple class:
public class MyClass {
public final static long MAIN = 1;
#Setter #Getter
protected int id;
}
(#Setter #Getter are lombok annotations for Setter and Getter methods.)
In Freemarker template I would like to create a condition like:
<#if myClassInstance.id == myClassInstance.MAIN>
But the right hand side of the if expression is according to FreeMarker undefined. Is there a way to do this? Thanks!
The template language is not aware of Java classes. But you can expose static members through the data-model (template context). See: http://freemarker.org/docs/pgui_misc_beanwrapper.html#autoid_55
I know that this question already have an accepted answer but I am still writing piece of code that can be help full for some one else.
Use below piece of code in java
BeansWrapper w = new BeansWrapper();
TemplateModel statics = w.getStaticModels();
map.put("statics", statics); // map is java.util.Map
template.process(map, out); // template is freemarker.template.Template
Then access constant in ftl
${statics["com.model.to.gen.Common"].FLAG_YES}
here com.model.to.gen.Common is a class and FLAG_YES is a static constant.
You can use expose fields option. So you can use data models without accessors (getters/setters).
BeansWrapperBuilder wrapperBuilder = new BeansWrapperBuilder(Configuration.VERSION_2_3_23);
wrapperBuilder.setExposeFields(true);
Template template = freemarkerConfiguration.getTemplate("mytemplatefile.ftl");
StringWriter stringWriter = new StringWriter();
template.process(model, stringWriter, wrapperBuilder.build());
System.out.println(stringWriter.toString());
I have another similar but effective way.
First, we can create a util class like this:
/**
* FreeMarker Utils.
*
* #author Eric Chan
*/
public abstract class FreeMarkerUtils {
/**
* init for static classes and fields.
*
* #param model model
*/
public static void initStatics(final Model model) {
// you can also create the Version like: new Version("2.3.27");
BeansWrapper wrapper = new BeansWrapper(new Version(2, 3, 27));
TemplateModel statics = wrapper.getStaticModels();
model.addAttribute("statics", statics);
}
}
And next, invoke it in your Controller:
FreeMarkerUtils.initStatics(model);
That's all, now you can access static variables in your .ftl like this:
${statics["com.springboot.constants.TestConstants"].NAME}

Validation with Struts 2 Convention plugin on method level, not class level

I have the a class, CouponAction, with two methods, initCoupon and addCoupon. I only want validation on the addCoupon method, not on class level where it tries to validate all methods.
this class with methods looks something like this
#Scope("prototype") #Controller
#Namespace("/coupon")
public class CouponAction extends BaseAjaxAction<Coupon> {
............
#Action(value = "initPaymentCoupons", results = {
#Result(location = "/jsp/order/coupon/paymentCoupon.jsp", name = "success")
})
public String initCoupons(){
........
}
#Validations(requiredFields = {
#RequiredFieldValidator(fieldName = "couponCode", type = ValidatorType.FIELD, message = "Enter a coupon code")
})
#Action(value = "/addCoupon", interceptorRefs=#InterceptorRef("jsonValidationWorkflowStack"),
results = {
#Result(location = "/jsp/order/coupon/paymentCoupon.jsp", name = "success")
})
public String addCoupon() {
.......
}
Then I get:
2011-11-10 00:44:13,567 ERROR org.apache.struts2.components.ActionComponent.error:38 - Could not execute action: /coupon/initCoupons
No result defined for action vervik.actions.order.CouponAction and result input
All examples Iv seen uses the validation annotation on class level.
When I used xml I had a file:
CouponAction-addCoupon-validation.xml
which only validation the addCoupon method.
How can I make it work with validation annotation?
Sources:
http://struts.apache.org/2.1.6/docs/convention-plugin.html#ConventionPlugin-InterceptorRefannotation
http://struts.apache.org/2.0.14/docs/annotations.html
What i am aware is that When multiple methods are used to map different actions on the same class, and one of them is annotated with #Validations, those validators will be triggered for all the actions.
Solution seems to use annotated with #SkipValidation or validateAnnotatedMethodOnly is set to true in the "validation" interceptor.
<interceptor-ref name="validation">
<param name="validateAnnotatedMethodOnly">true</param>
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
refer the following link
Struts2 Validation
though even i have not worked with such case using annotation so hope this will work for you.
You can use #SkipValidation annotation at the method level to bypass the initCoupons() method.

Spring getBean with type validation

I'm using the method ApplicationContext.getBean(String name, Class requiredType). The bean is of type util:set. My code looks like:
Set<String> mySet = context.getBean("myBean", Set.class);
I want to know is how to do something like this to avoid the type casting warning:
Set<String> mySet = context.getBean("myBean", Set<String>.class);
I'm not sure if it's possible to define the type of a class in this way. Am I dreaming or is there a way to do this?
Thanks.
Not really but there is a runtime workaround that at least removes the need for an #SuppressWarnings. You can make your class abstract and let Spring instrument your code:
public abstract class Test {
Set<String> getMyBean();
}
and then inject a lookup method in your XML config:
<bean class="Test">
<lookup-method name="myBean" bean="myBean" />
</bean>
It's not really statically checked but it fails-fast at runtime and you keep the ugly casting out of your code.
maybe this can be usefull to you:
Set<String> setBean= null;
Map<String, Set> beans = applicationContext.getBeansOfType(Set.class);
for (Map.Entry<String, Set> bean: beans.entrySet()) {
ParameterizedType thisType = (ParameterizedType) bean.getClass().getGenericSuperclass();
Class<?> parametrizedClass= thisType.getActualTypeArguments()[0];
if (parametrizedClass.isAssignableFrom(String)) {
setBean= (Set<String>) bean;
}
}
http://javahelp.redsaltillo.net

Resources